"Fossies" - the Fresh Open Source Software Archive

Member "apr-1.7.0/misc/unix/rand.c" (21 Jun 2018, 7572 Bytes) of package /linux/www/apr-1.7.0.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "rand.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.6.5_vs_1.7.0.

    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 {
   98     uuid_t g;
   99 
  100     uuid_generate(g);
  101 
  102     memcpy(uuid_data, g, sizeof(uuid_t));
  103 
  104     return APR_SUCCESS;
  105 }
  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 {
  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     do {
  214         int rc;
  215 
  216         rc = getrandom(buf, length, 0);
  217         if (rc == -1) {
  218             if (errno == EINTR) {
  219                 continue;
  220             }
  221             return errno;
  222         }
  223 
  224         buf += rc;
  225         length -= rc;
  226     } 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     return APR_SUCCESS;
  293 }
  294 
  295 #undef  STR
  296 #undef  XSTR
  297 
  298 #ifdef OS2
  299 #include "randbyte_os2.inc"
  300 #endif
  301 
  302 #endif /* APR_HAS_RANDOM */