Blame crypto/getuuid.c

Packit 383869
/* Licensed to the Apache Software Foundation (ASF) under one or more
Packit 383869
 * contributor license agreements.  See the NOTICE file distributed with
Packit 383869
 * this work for additional information regarding copyright ownership.
Packit 383869
 * The ASF licenses this file to You under the Apache License, Version 2.0
Packit 383869
 * (the "License"); you may not use this file except in compliance with
Packit 383869
 * the License.  You may obtain a copy of the License at
Packit 383869
 *
Packit 383869
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 383869
 *
Packit 383869
 * Unless required by applicable law or agreed to in writing, software
Packit 383869
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 383869
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 383869
 * See the License for the specific language governing permissions and
Packit 383869
 * limitations under the License.
Packit 383869
 */
Packit 383869
Packit 383869
/*
Packit 383869
 * This attempts to generate V1 UUIDs according to the Internet Draft
Packit 383869
 * located at http://www.webdav.org/specs/draft-leach-uuids-guids-01.txt
Packit 383869
 */
Packit 383869
#include "apr.h"
Packit 383869
#include "apr_uuid.h"
Packit 383869
#include "apr_md5.h"
Packit 383869
#include "apr_general.h"
Packit 383869
#include "apr_portable.h"
Packit 383869
Packit 383869
Packit 383869
#if APR_HAVE_UNISTD_H
Packit 383869
#include <unistd.h>     /* for getpid, gethostname */
Packit 383869
#endif
Packit 383869
#if APR_HAVE_STDLIB_H
Packit 383869
#include <stdlib.h>     /* for rand, srand */
Packit 383869
#endif
Packit 383869
Packit 383869
Packit 383869
#if APR_HAVE_STRING_H
Packit 383869
#include <string.h>
Packit 383869
#endif
Packit 383869
#if APR_HAVE_STRINGS_H
Packit 383869
#include <strings.h>
Packit 383869
#endif
Packit 383869
#if APR_HAVE_NETDB_H
Packit 383869
#include <netdb.h>
Packit 383869
#endif
Packit 383869
#if APR_HAVE_SYS_TIME_H
Packit 383869
#include <sys/time.h>   /* for gettimeofday */
Packit 383869
#endif
Packit 383869
Packit 383869
#define NODE_LENGTH 6
Packit 383869
Packit 383869
static int uuid_state_seqnum;
Packit 383869
static unsigned char uuid_state_node[NODE_LENGTH] = { 0 };
Packit 383869
Packit 383869
Packit 383869
static void get_random_info(unsigned char node[NODE_LENGTH])
Packit 383869
{
Packit 383869
#if APR_HAS_RANDOM
Packit 383869
Packit 383869
    (void) apr_generate_random_bytes(node, NODE_LENGTH);
Packit 383869
Packit 383869
#else
Packit 383869
Packit 383869
    unsigned char seed[APR_MD5_DIGESTSIZE];
Packit 383869
    apr_md5_ctx_t c;
Packit 383869
Packit 383869
    /* ### probably should revise some of this to be a bit more portable */
Packit 383869
Packit 383869
    /* Leach & Salz use Linux-specific struct sysinfo;
Packit 383869
     * replace with pid/tid for portability (in the spirit of mod_unique_id) */
Packit 383869
    struct {
Packit 383869
	/* Add thread id here, if applicable, when we get to pthread or apr */
Packit 383869
        pid_t pid;
Packit 383869
#ifdef NETWARE
Packit 383869
        apr_uint64_t t;
Packit 383869
#else
Packit 383869
        struct timeval t;
Packit 383869
#endif
Packit 383869
        char hostname[257];
Packit 383869
Packit 383869
    } r;
Packit 383869
Packit 383869
    apr_md5_init(&c);
Packit 383869
#ifdef NETWARE
Packit 383869
    r.pid = NXThreadGetId();
Packit 383869
    NXGetTime(NX_SINCE_BOOT, NX_USECONDS, &(r.t));
Packit 383869
#else
Packit 383869
    r.pid = getpid();
Packit 383869
    gettimeofday(&r.t, (struct timezone *)0);
Packit 383869
#endif
Packit 383869
    gethostname(r.hostname, 256);
Packit 383869
    apr_md5_update(&c, (const unsigned char *)&r, sizeof(r));
Packit 383869
    apr_md5_final(seed, &c);
Packit 383869
Packit 383869
    memcpy(node, seed, NODE_LENGTH);    /* use a subset of the seed bytes */
Packit 383869
#endif
Packit 383869
}
Packit 383869
Packit 383869
/* This implementation generates a random node ID instead of a
Packit 383869
   system-dependent call to get IEEE node ID. This is also more secure:
Packit 383869
   we aren't passing out our MAC address.
Packit 383869
*/
Packit 383869
static void get_pseudo_node_identifier(unsigned char *node)
Packit 383869
{
Packit 383869
    get_random_info(node);
Packit 383869
    node[0] |= 0x01;                    /* this designates a random multicast node ID */
Packit 383869
}
Packit 383869
Packit 383869
static void get_system_time(apr_uint64_t *uuid_time)
Packit 383869
{
Packit 383869
    /* ### fix this call to be more portable? */
Packit 383869
    *uuid_time = apr_time_now();
Packit 383869
Packit 383869
    /* Offset between UUID formatted times and Unix formatted times.
Packit 383869
       UUID UTC base time is October 15, 1582.
Packit 383869
       Unix base time is January 1, 1970.      */
Packit 383869
    *uuid_time = (*uuid_time * 10) + APR_TIME_C(0x01B21DD213814000);
Packit 383869
}
Packit 383869
Packit 383869
/* true_random -- generate a crypto-quality random number. */
Packit 383869
static int true_random(void)
Packit 383869
{
Packit 383869
    apr_uint64_t time_now;
Packit 383869
Packit 383869
#if APR_HAS_RANDOM
Packit 383869
    unsigned char buf[2];
Packit 383869
Packit 383869
    if (apr_generate_random_bytes(buf, 2) == APR_SUCCESS) {
Packit 383869
        return (buf[0] << 8) | buf[1];
Packit 383869
    }
Packit 383869
#endif
Packit 383869
Packit 383869
    /* crap. this isn't crypto quality, but it will be Good Enough */
Packit 383869
Packit 383869
    time_now = apr_time_now();
Packit 383869
    srand((unsigned int)(((time_now >> 32) ^ time_now) & 0xffffffff));
Packit 383869
Packit 383869
    return rand() & 0x0FFFF;
Packit 383869
}
Packit 383869
Packit 383869
static void init_state(void)
Packit 383869
{
Packit 383869
    uuid_state_seqnum = true_random();
Packit 383869
    get_pseudo_node_identifier(uuid_state_node);
Packit 383869
}
Packit 383869
Packit 383869
static void get_current_time(apr_uint64_t *timestamp)
Packit 383869
{
Packit 383869
    /* ### this needs to be made thread-safe! */
Packit 383869
Packit 383869
    apr_uint64_t time_now;
Packit 383869
    static apr_uint64_t time_last = 0;
Packit 383869
    static apr_uint64_t fudge = 0;
Packit 383869
Packit 383869
    get_system_time(&time_now);
Packit 383869
        
Packit 383869
    /* if clock reading changed since last UUID generated... */
Packit 383869
    if (time_last != time_now) {
Packit 383869
        /* The clock reading has changed since the last UUID was generated.
Packit 383869
           Reset the fudge factor. if we are generating them too fast, then
Packit 383869
           the fudge may need to be reset to something greater than zero. */
Packit 383869
        if (time_last + fudge > time_now)
Packit 383869
            fudge = time_last + fudge - time_now + 1;
Packit 383869
        else
Packit 383869
            fudge = 0;
Packit 383869
        time_last = time_now;
Packit 383869
    }
Packit 383869
    else {
Packit 383869
        /* We generated two really fast. Bump the fudge factor. */
Packit 383869
        ++fudge;
Packit 383869
    }
Packit 383869
Packit 383869
    *timestamp = time_now + fudge;
Packit 383869
}
Packit 383869
Packit 383869
APU_DECLARE(void) apr_uuid_get(apr_uuid_t *uuid)
Packit 383869
{
Packit 383869
    apr_uint64_t timestamp;
Packit 383869
    unsigned char *d = uuid->data;
Packit 383869
Packit 383869
#if APR_HAS_OS_UUID
Packit 383869
    if (apr_os_uuid_get(d) == APR_SUCCESS) {
Packit 383869
        return;
Packit 383869
    }
Packit 383869
#endif /* !APR_HAS_OS_UUID */
Packit 383869
Packit 383869
    if (!uuid_state_node[0])
Packit 383869
        init_state();
Packit 383869
Packit 383869
    get_current_time(&timestamp);
Packit 383869
Packit 383869
    /* time_low, uint32 */
Packit 383869
    d[3] = (unsigned char)timestamp;
Packit 383869
    d[2] = (unsigned char)(timestamp >> 8);
Packit 383869
    d[1] = (unsigned char)(timestamp >> 16);
Packit 383869
    d[0] = (unsigned char)(timestamp >> 24);
Packit 383869
    /* time_mid, uint16 */
Packit 383869
    d[5] = (unsigned char)(timestamp >> 32);
Packit 383869
    d[4] = (unsigned char)(timestamp >> 40);
Packit 383869
    /* time_hi_and_version, uint16 */
Packit 383869
    d[7] = (unsigned char)(timestamp >> 48);
Packit 383869
    d[6] = (unsigned char)(((timestamp >> 56) & 0x0F) | 0x10);
Packit 383869
    /* clock_seq_hi_and_reserved, uint8 */
Packit 383869
    d[8] = (unsigned char)(((uuid_state_seqnum >> 8) & 0x3F) | 0x80);
Packit 383869
    /* clock_seq_low, uint8 */
Packit 383869
    d[9] = (unsigned char)uuid_state_seqnum;
Packit 383869
    /* node, byte[6] */
Packit 383869
    memcpy(&d[10], uuid_state_node, NODE_LENGTH);
Packit 383869
}