freebsd-dev/contrib/apr/misc/unix/rand.c
Peter Wemm 937a200089 Introduce svnlite so that we can check out our source code again.
This is actually a fully functional build except:
* All internal shared libraries are static linked to make sure there
  is no interference with ports (and to reduce build time).
* It does not have the python/perl/etc plugin or API support.
* By default, it installs as "svnlite" rather than "svn".
* If WITH_SVN added in make.conf, you get "svn".
* If WITHOUT_SVNLITE is in make.conf, this is completely disabled.

To be absolutely clear, this is not intended for any use other than
checking out freebsd source and committing, like we once did with cvs.

It should be usable for small scale local repositories that don't
need the python/perl plugin architecture.
2013-06-18 02:53:45 +00:00

251 lines
6.4 KiB
C

/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define APR_WANT_MEMFUNC
#include "apr_want.h"
#include "apr_general.h"
#include "apr_arch_misc.h"
#include <sys/stat.h>
#if APR_HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#if APR_HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#if APR_HAVE_FCNTL_H
#include <fcntl.h>
#endif
#if APR_HAVE_UNISTD_H
#include <unistd.h>
#endif
#if APR_HAVE_SYS_UN_H
#include <sys/un.h>
#endif
#if defined(HAVE_UUID_H)
#include <uuid.h>
#elif defined(HAVE_UUID_UUID_H)
#include <uuid/uuid.h>
#elif defined(HAVE_SYS_UUID_H)
#include <sys/uuid.h>
#endif
#ifndef SHUT_RDWR
#define SHUT_RDWR 2
#endif
#if APR_HAS_OS_UUID
#if defined(HAVE_UUID_CREATE)
APR_DECLARE(apr_status_t) apr_os_uuid_get(unsigned char *uuid_data)
{
uint32_t rv;
uuid_t g;
uuid_create(&g, &rv);
if (rv != uuid_s_ok)
return APR_EGENERAL;
memcpy(uuid_data, &g, sizeof(uuid_t));
return APR_SUCCESS;
}
#elif defined(HAVE_UUID_GENERATE)
APR_DECLARE(apr_status_t) apr_os_uuid_get(unsigned char *uuid_data)
{
uuid_t g;
uuid_generate(g);
memcpy(uuid_data, g, sizeof(uuid_t));
return APR_SUCCESS;
}
#endif
#endif /* APR_HAS_OS_UUID */
#if APR_HAS_RANDOM
APR_DECLARE(apr_status_t) apr_generate_random_bytes(unsigned char *buf,
apr_size_t length)
{
#ifdef DEV_RANDOM
int fd = -1;
/* On BSD/OS 4.1, /dev/random gives out 8 bytes at a time, then
* gives EOF, so reading 'length' bytes may require opening the
* device several times. */
do {
apr_ssize_t rc;
if (fd == -1)
if ((fd = open(DEV_RANDOM, O_RDONLY)) == -1)
return errno;
do {
rc = read(fd, buf, length);
} while (rc == -1 && errno == EINTR);
if (rc < 0) {
int errnum = errno;
close(fd);
return errnum;
}
else if (rc == 0) {
close(fd);
fd = -1; /* force open() again */
}
else {
buf += rc;
length -= rc;
}
} while (length > 0);
close(fd);
#elif defined(OS2)
static UCHAR randbyte();
unsigned int idx;
for (idx=0; idx<length; idx++)
buf[idx] = randbyte();
#elif defined(HAVE_EGD)
/* use EGD-compatible socket daemon (such as EGD or PRNGd).
* message format:
* 0x00 (get entropy level)
* 0xMM (msb) 0xmm 0xll 0xLL (lsb)
* 0x01 (read entropy nonblocking) 0xNN (bytes requested)
* 0xMM (bytes granted) MM bytes
* 0x02 (read entropy blocking) 0xNN (bytes desired)
* [block] NN bytes
* 0x03 (write entropy) 0xMM 0xLL (bits of entropy) 0xNN (bytes of data)
* NN bytes
* (no response - write only)
* 0x04 (report PID)
* 0xMM (length of PID string, not null-terminated) MM chars
*/
static const char *egd_sockets[] = { EGD_DEFAULT_SOCKET, NULL };
const char **egdsockname = NULL;
int egd_socket, egd_path_len, rv, bad_errno;
struct sockaddr_un addr;
apr_socklen_t egd_addr_len;
apr_size_t resp_expected;
unsigned char req[2], resp[255];
unsigned char *curbuf = buf;
for (egdsockname = egd_sockets; *egdsockname && length > 0; egdsockname++) {
egd_path_len = strlen(*egdsockname);
if (egd_path_len > sizeof(addr.sun_path)) {
return APR_EINVAL;
}
memset(&addr, 0, sizeof(struct sockaddr_un));
addr.sun_family = AF_UNIX;
memcpy(addr.sun_path, *egdsockname, egd_path_len);
egd_addr_len = APR_OFFSETOF(struct sockaddr_un, sun_path) +
egd_path_len;
egd_socket = socket(PF_UNIX, SOCK_STREAM, 0);
if (egd_socket == -1) {
return errno;
}
rv = connect(egd_socket, (struct sockaddr*)&addr, egd_addr_len);
if (rv == -1) {
bad_errno = errno;
continue;
}
/* EGD can only return 255 bytes of data at a time. Silly. */
while (length > 0) {
apr_ssize_t srv;
req[0] = 2; /* We'll block for now. */
req[1] = length > 255 ? 255: length;
srv = write(egd_socket, req, 2);
if (srv == -1) {
bad_errno = errno;
shutdown(egd_socket, SHUT_RDWR);
close(egd_socket);
break;
}
if (srv != 2) {
shutdown(egd_socket, SHUT_RDWR);
close(egd_socket);
return APR_EGENERAL;
}
resp_expected = req[1];
srv = read(egd_socket, resp, resp_expected);
if (srv == -1) {
bad_errno = errno;
shutdown(egd_socket, SHUT_RDWR);
close(egd_socket);
return bad_errno;
}
memcpy(curbuf, resp, srv);
curbuf += srv;
length -= srv;
}
shutdown(egd_socket, SHUT_RDWR);
close(egd_socket);
}
if (length > 0) {
/* We must have iterated through the list of sockets,
* and no go. Return the errno.
*/
return bad_errno;
}
#elif defined(HAVE_TRUERAND) /* use truerand */
extern int randbyte(void); /* from the truerand library */
unsigned int idx;
/* this will increase the startup time of the server, unfortunately...
* (generating 20 bytes takes about 8 seconds)
*/
for (idx=0; idx<length; idx++)
buf[idx] = (unsigned char) randbyte();
#endif /* DEV_RANDOM */
return APR_SUCCESS;
}
#undef STR
#undef XSTR
#ifdef OS2
#include "randbyte_os2.inc"
#endif
#endif /* APR_HAS_RANDOM */