Annotation of embedaddon/ntp/lib/isc/entropy.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2004-2007, 2009  Internet Systems Consortium, Inc. ("ISC")
                      3:  * Copyright (C) 2000-2003  Internet Software Consortium.
                      4:  *
                      5:  * Permission to use, copy, modify, and/or distribute this software for any
                      6:  * purpose with or without fee is hereby granted, provided that the above
                      7:  * copyright notice and this permission notice appear in all copies.
                      8:  *
                      9:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
                     10:  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
                     11:  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
                     12:  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
                     13:  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
                     14:  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
                     15:  * PERFORMANCE OF THIS SOFTWARE.
                     16:  */
                     17: 
                     18: /* $Id: entropy.c,v 1.18.332.2 2009/01/18 23:47:41 tbox Exp $ */
                     19: 
                     20: /*! \file
                     21:  * \brief
                     22:  * This is the system independent part of the entropy module.  It is
                     23:  * compiled via inclusion from the relevant OS source file, ie,
                     24:  * \link unix/entropy.c unix/entropy.c \endlink or win32/entropy.c.
                     25:  *
                     26:  * \author Much of this code is modeled after the NetBSD /dev/random implementation,
                     27:  * written by Michael Graff <explorer@netbsd.org>.
                     28:  */
                     29: 
                     30: #include <errno.h>
                     31: #include <fcntl.h>
                     32: #include <stdio.h>
                     33: 
                     34: #include <isc/buffer.h>
                     35: #include <isc/entropy.h>
                     36: #include <isc/keyboard.h>
                     37: #include <isc/list.h>
                     38: #include <isc/magic.h>
                     39: #include <isc/mem.h>
                     40: #include <isc/msgs.h>
                     41: #include <isc/mutex.h>
                     42: #include <isc/platform.h>
                     43: #include <isc/region.h>
                     44: #include <isc/sha1.h>
                     45: #include <isc/string.h>
                     46: #include <isc/time.h>
                     47: #include <isc/util.h>
                     48: 
                     49: 
                     50: #define ENTROPY_MAGIC          ISC_MAGIC('E', 'n', 't', 'e')
                     51: #define SOURCE_MAGIC           ISC_MAGIC('E', 'n', 't', 's')
                     52: 
                     53: #define VALID_ENTROPY(e)       ISC_MAGIC_VALID(e, ENTROPY_MAGIC)
                     54: #define VALID_SOURCE(s)                ISC_MAGIC_VALID(s, SOURCE_MAGIC)
                     55: 
                     56: /***
                     57:  *** "constants."  Do not change these unless you _really_ know what
                     58:  *** you are doing.
                     59:  ***/
                     60: 
                     61: /*%
                     62:  * Size of entropy pool in 32-bit words.  This _MUST_ be a power of 2.
                     63:  */
                     64: #define RND_POOLWORDS  128
                     65: /*% Pool in bytes. */
                     66: #define RND_POOLBYTES  (RND_POOLWORDS * 4)
                     67: /*% Pool in bits. */
                     68: #define RND_POOLBITS   (RND_POOLWORDS * 32)
                     69: 
                     70: /*%
                     71:  * Number of bytes returned per hash.  This must be true:
                     72:  *     threshold * 2 <= digest_size_in_bytes
                     73:  */
                     74: #define RND_ENTROPY_THRESHOLD  10
                     75: #define THRESHOLD_BITS         (RND_ENTROPY_THRESHOLD * 8)
                     76: 
                     77: /*%
                     78:  * Size of the input event queue in samples.
                     79:  */
                     80: #define RND_EVENTQSIZE 32
                     81: 
                     82: /*%
                     83:  * The number of times we'll "reseed" for pseudorandom seeds.  This is an
                     84:  * extremely weak pseudorandom seed.  If the caller is using lots of
                     85:  * pseudorandom data and they cannot provide a stronger random source,
                     86:  * there is little we can do other than hope they're smart enough to
                     87:  * call _adddata() with something better than we can come up with.
                     88:  */
                     89: #define RND_INITIALIZE 128
                     90: 
                     91: /*% Entropy Pool */
                     92: typedef struct {
                     93:        isc_uint32_t    cursor;         /*%< current add point in the pool */
                     94:        isc_uint32_t    entropy;        /*%< current entropy estimate in bits */
                     95:        isc_uint32_t    pseudo;         /*%< bits extracted in pseudorandom */
                     96:        isc_uint32_t    rotate;         /*%< how many bits to rotate by */
                     97:        isc_uint32_t    pool[RND_POOLWORDS];    /*%< random pool data */
                     98: } isc_entropypool_t;
                     99: 
                    100: struct isc_entropy {
                    101:        unsigned int                    magic;
                    102:        isc_mem_t                      *mctx;
                    103:        isc_mutex_t                     lock;
                    104:        unsigned int                    refcnt;
                    105:        isc_uint32_t                    initialized;
                    106:        isc_uint32_t                    initcount;
                    107:        isc_entropypool_t               pool;
                    108:        unsigned int                    nsources;
                    109:        isc_entropysource_t            *nextsource;
                    110:        ISC_LIST(isc_entropysource_t)   sources;
                    111: };
                    112: 
                    113: /*% Sample Queue */
                    114: typedef struct {
                    115:        isc_uint32_t    last_time;      /*%< last time recorded */
                    116:        isc_uint32_t    last_delta;     /*%< last delta value */
                    117:        isc_uint32_t    last_delta2;    /*%< last delta2 value */
                    118:        isc_uint32_t    nsamples;       /*%< number of samples filled in */
                    119:        isc_uint32_t   *samples;        /*%< the samples */
                    120:        isc_uint32_t   *extra;          /*%< extra samples added in */
                    121: } sample_queue_t;
                    122: 
                    123: typedef struct {
                    124:        sample_queue_t  samplequeue;
                    125: } isc_entropysamplesource_t;
                    126: 
                    127: typedef struct {
                    128:        isc_boolean_t           start_called;
                    129:        isc_entropystart_t      startfunc;
                    130:        isc_entropyget_t        getfunc;
                    131:        isc_entropystop_t       stopfunc;
                    132:        void                   *arg;
                    133:        sample_queue_t          samplequeue;
                    134: } isc_cbsource_t;
                    135: 
                    136: typedef struct {
                    137:        FILESOURCE_HANDLE_TYPE handle;
                    138: } isc_entropyfilesource_t;
                    139: 
                    140: struct isc_entropysource {
                    141:        unsigned int    magic;
                    142:        unsigned int    type;
                    143:        isc_entropy_t  *ent;
                    144:        isc_uint32_t    total;          /*%< entropy from this source */
                    145:        ISC_LINK(isc_entropysource_t)   link;
                    146:        char            name[32];
                    147:        isc_boolean_t   bad;
                    148:        isc_boolean_t   warn_keyboard;
                    149:        isc_keyboard_t  kbd;
                    150:        union {
                    151:                isc_entropysamplesource_t       sample;
                    152:                isc_entropyfilesource_t         file;
                    153:                isc_cbsource_t                  callback;
                    154:                isc_entropyusocketsource_t      usocket;
                    155:        } sources;
                    156: };
                    157: 
                    158: #define ENTROPY_SOURCETYPE_SAMPLE      1       /*%< Type is a sample source */
                    159: #define ENTROPY_SOURCETYPE_FILE                2       /*%< Type is a file source */
                    160: #define ENTROPY_SOURCETYPE_CALLBACK    3       /*%< Type is a callback source */
                    161: #define ENTROPY_SOURCETYPE_USOCKET     4       /*%< Type is a Unix socket source */
                    162: 
                    163: /*@{*/
                    164: /*%
                    165:  * The random pool "taps"
                    166:  */
                    167: #define TAP1   99
                    168: #define TAP2   59
                    169: #define TAP3   31
                    170: #define TAP4    9
                    171: #define TAP5    7
                    172: /*@}*/
                    173: 
                    174: /*@{*/
                    175: /*%
                    176:  * Declarations for function provided by the system dependent sources that
                    177:  * include this file.
                    178:  */
                    179: static void
                    180: fillpool(isc_entropy_t *, unsigned int, isc_boolean_t);
                    181: 
                    182: static int
                    183: wait_for_sources(isc_entropy_t *);
                    184: 
                    185: static void
                    186: destroyfilesource(isc_entropyfilesource_t *source);
                    187: 
                    188: static void
                    189: destroyusocketsource(isc_entropyusocketsource_t *source);
                    190: 
                    191: /*@}*/
                    192: 
                    193: static void
                    194: samplequeue_release(isc_entropy_t *ent, sample_queue_t *sq) {
                    195:        REQUIRE(sq->samples != NULL);
                    196:        REQUIRE(sq->extra != NULL);
                    197: 
                    198:        isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4);
                    199:        isc_mem_put(ent->mctx, sq->extra, RND_EVENTQSIZE * 4);
                    200:        sq->samples = NULL;
                    201:        sq->extra = NULL;
                    202: }
                    203: 
                    204: static isc_result_t
                    205: samplesource_allocate(isc_entropy_t *ent, sample_queue_t *sq) {
                    206:        sq->samples = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4);
                    207:        if (sq->samples == NULL)
                    208:                return (ISC_R_NOMEMORY);
                    209: 
                    210:        sq->extra = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4);
                    211:        if (sq->extra == NULL) {
                    212:                isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4);
                    213:                sq->samples = NULL;
                    214:                return (ISC_R_NOMEMORY);
                    215:        }
                    216: 
                    217:        sq->nsamples = 0;
                    218: 
                    219:        return (ISC_R_SUCCESS);
                    220: }
                    221: 
                    222: /*%
                    223:  * Add in entropy, even when the value we're adding in could be
                    224:  * very large.
                    225:  */
                    226: static inline void
                    227: add_entropy(isc_entropy_t *ent, isc_uint32_t entropy) {
                    228:        /* clamp input.  Yes, this must be done. */
                    229:        entropy = ISC_MIN(entropy, RND_POOLBITS);
                    230:        /* Add in the entropy we already have. */
                    231:        entropy += ent->pool.entropy;
                    232:        /* Clamp. */
                    233:        ent->pool.entropy = ISC_MIN(entropy, RND_POOLBITS);
                    234: }
                    235: 
                    236: /*%
                    237:  * Decrement the amount of entropy the pool has.
                    238:  */
                    239: static inline void
                    240: subtract_entropy(isc_entropy_t *ent, isc_uint32_t entropy) {
                    241:        entropy = ISC_MIN(entropy, ent->pool.entropy);
                    242:        ent->pool.entropy -= entropy;
                    243: }
                    244: 
                    245: /*!
                    246:  * Add in entropy, even when the value we're adding in could be
                    247:  * very large.
                    248:  */
                    249: static inline void
                    250: add_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) {
                    251:        /* clamp input.  Yes, this must be done. */
                    252:        pseudo = ISC_MIN(pseudo, RND_POOLBITS * 8);
                    253:        /* Add in the pseudo we already have. */
                    254:        pseudo += ent->pool.pseudo;
                    255:        /* Clamp. */
                    256:        ent->pool.pseudo = ISC_MIN(pseudo, RND_POOLBITS * 8);
                    257: }
                    258: 
                    259: /*!
                    260:  * Decrement the amount of pseudo the pool has.
                    261:  */
                    262: static inline void
                    263: subtract_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) {
                    264:        pseudo = ISC_MIN(pseudo, ent->pool.pseudo);
                    265:        ent->pool.pseudo -= pseudo;
                    266: }
                    267: 
                    268: /*!
                    269:  * Add one word to the pool, rotating the input as needed.
                    270:  */
                    271: static inline void
                    272: entropypool_add_word(isc_entropypool_t *rp, isc_uint32_t val) {
                    273:        /*
                    274:         * Steal some values out of the pool, and xor them into the
                    275:         * word we were given.
                    276:         *
                    277:         * Mix the new value into the pool using xor.  This will
                    278:         * prevent the actual values from being known to the caller
                    279:         * since the previous values are assumed to be unknown as well.
                    280:         */
                    281:        val ^= rp->pool[(rp->cursor + TAP1) & (RND_POOLWORDS - 1)];
                    282:        val ^= rp->pool[(rp->cursor + TAP2) & (RND_POOLWORDS - 1)];
                    283:        val ^= rp->pool[(rp->cursor + TAP3) & (RND_POOLWORDS - 1)];
                    284:        val ^= rp->pool[(rp->cursor + TAP4) & (RND_POOLWORDS - 1)];
                    285:        val ^= rp->pool[(rp->cursor + TAP5) & (RND_POOLWORDS - 1)];
                    286:        rp->pool[rp->cursor++] ^=
                    287:          ((val << rp->rotate) | (val >> (32 - rp->rotate)));
                    288: 
                    289:        /*
                    290:         * If we have looped around the pool, increment the rotate
                    291:         * variable so the next value will get xored in rotated to
                    292:         * a different position.
                    293:         * Increment by a value that is relatively prime to the word size
                    294:         * to try to spread the bits throughout the pool quickly when the
                    295:         * pool is empty.
                    296:         */
                    297:        if (rp->cursor == RND_POOLWORDS) {
                    298:                rp->cursor = 0;
                    299:                rp->rotate = (rp->rotate + 7) & 31;
                    300:        }
                    301: }
                    302: 
                    303: /*!
                    304:  * Add a buffer's worth of data to the pool.
                    305:  *
                    306:  * Requires that the lock is held on the entropy pool.
                    307:  */
                    308: static void
                    309: entropypool_adddata(isc_entropy_t *ent, void *p, unsigned int len,
                    310:                    isc_uint32_t entropy)
                    311: {
                    312:        isc_uint32_t val;
                    313:        unsigned long addr;
                    314:        isc_uint8_t *buf;
                    315: 
                    316:        addr = (unsigned long)p;
                    317:        buf = p;
                    318: 
                    319:        if ((addr & 0x03U) != 0U) {
                    320:                val = 0;
                    321:                switch (len) {
                    322:                case 3:
                    323:                        val = *buf++;
                    324:                        len--;
                    325:                case 2:
                    326:                        val = val << 8 | *buf++;
                    327:                        len--;
                    328:                case 1:
                    329:                        val = val << 8 | *buf++;
                    330:                        len--;
                    331:                }
                    332: 
                    333:                entropypool_add_word(&ent->pool, val);
                    334:        }
                    335: 
                    336:        for (; len > 3; len -= 4) {
                    337:                val = *((isc_uint32_t *)buf);
                    338: 
                    339:                entropypool_add_word(&ent->pool, val);
                    340:                buf += 4;
                    341:        }
                    342: 
                    343:        if (len != 0) {
                    344:                val = 0;
                    345:                switch (len) {
                    346:                case 3:
                    347:                        val = *buf++;
                    348:                case 2:
                    349:                        val = val << 8 | *buf++;
                    350:                case 1:
                    351:                        val = val << 8 | *buf++;
                    352:                }
                    353: 
                    354:                entropypool_add_word(&ent->pool, val);
                    355:        }
                    356: 
                    357:        add_entropy(ent, entropy);
                    358:        subtract_pseudo(ent, entropy);
                    359: }
                    360: 
                    361: static inline void
                    362: reseed(isc_entropy_t *ent) {
                    363:        isc_time_t t;
                    364:        pid_t pid;
                    365: 
                    366:        if (ent->initcount == 0) {
                    367:                pid = getpid();
                    368:                entropypool_adddata(ent, &pid, sizeof(pid), 0);
                    369:                pid = getppid();
                    370:                entropypool_adddata(ent, &pid, sizeof(pid), 0);
                    371:        }
                    372: 
                    373:        /*!
                    374:         * After we've reseeded 100 times, only add new timing info every
                    375:         * 50 requests.  This will keep us from using lots and lots of
                    376:         * CPU just to return bad pseudorandom data anyway.
                    377:         */
                    378:        if (ent->initcount > 100)
                    379:                if ((ent->initcount % 50) != 0)
                    380:                        return;
                    381: 
                    382:        TIME_NOW(&t);
                    383:        entropypool_adddata(ent, &t, sizeof(t), 0);
                    384:        ent->initcount++;
                    385: }
                    386: 
                    387: static inline unsigned int
                    388: estimate_entropy(sample_queue_t *sq, isc_uint32_t t) {
                    389:        isc_int32_t             delta;
                    390:        isc_int32_t             delta2;
                    391:        isc_int32_t             delta3;
                    392: 
                    393:        /*!
                    394:         * If the time counter has overflowed, calculate the real difference.
                    395:         * If it has not, it is simpler.
                    396:         */
                    397:        if (t < sq->last_time)
                    398:                delta = UINT_MAX - sq->last_time + t;
                    399:        else
                    400:                delta = sq->last_time - t;
                    401: 
                    402:        if (delta < 0)
                    403:                delta = -delta;
                    404: 
                    405:        /*
                    406:         * Calculate the second and third order differentials
                    407:         */
                    408:        delta2 = sq->last_delta - delta;
                    409:        if (delta2 < 0)
                    410:                delta2 = -delta2;
                    411: 
                    412:        delta3 = sq->last_delta2 - delta2;
                    413:        if (delta3 < 0)
                    414:                delta3 = -delta3;
                    415: 
                    416:        sq->last_time = t;
                    417:        sq->last_delta = delta;
                    418:        sq->last_delta2 = delta2;
                    419: 
                    420:        /*
                    421:         * If any delta is 0, we got no entropy.  If all are non-zero, we
                    422:         * might have something.
                    423:         */
                    424:        if (delta == 0 || delta2 == 0 || delta3 == 0)
                    425:                return 0;
                    426: 
                    427:        /*
                    428:         * We could find the smallest delta and claim we got log2(delta)
                    429:         * bits, but for now return that we found 1 bit.
                    430:         */
                    431:        return 1;
                    432: }
                    433: 
                    434: static unsigned int
                    435: crunchsamples(isc_entropy_t *ent, sample_queue_t *sq) {
                    436:        unsigned int ns;
                    437:        unsigned int added;
                    438: 
                    439:        if (sq->nsamples < 6)
                    440:                return (0);
                    441: 
                    442:        added = 0;
                    443:        sq->last_time = sq->samples[0];
                    444:        sq->last_delta = 0;
                    445:        sq->last_delta2 = 0;
                    446: 
                    447:        /*
                    448:         * Prime the values by adding in the first 4 samples in.  This
                    449:         * should completely initialize the delta calculations.
                    450:         */
                    451:        for (ns = 0; ns < 4; ns++)
                    452:                (void)estimate_entropy(sq, sq->samples[ns]);
                    453: 
                    454:        for (ns = 4; ns < sq->nsamples; ns++)
                    455:                added += estimate_entropy(sq, sq->samples[ns]);
                    456: 
                    457:        entropypool_adddata(ent, sq->samples, sq->nsamples * 4, added);
                    458:        entropypool_adddata(ent, sq->extra, sq->nsamples * 4, 0);
                    459: 
                    460:        /*
                    461:         * Move the last 4 samples into the first 4 positions, and start
                    462:         * adding new samples from that point.
                    463:         */
                    464:        for (ns = 0; ns < 4; ns++) {
                    465:                sq->samples[ns] = sq->samples[sq->nsamples - 4 + ns];
                    466:                sq->extra[ns] = sq->extra[sq->nsamples - 4 + ns];
                    467:        }
                    468: 
                    469:        sq->nsamples = 4;
                    470: 
                    471:        return (added);
                    472: }
                    473: 
                    474: static unsigned int
                    475: get_from_callback(isc_entropysource_t *source, unsigned int desired,
                    476:                  isc_boolean_t blocking)
                    477: {
                    478:        isc_entropy_t *ent = source->ent;
                    479:        isc_cbsource_t *cbs = &source->sources.callback;
                    480:        unsigned int added;
                    481:        unsigned int got;
                    482:        isc_result_t result;
                    483: 
                    484:        if (desired == 0)
                    485:                return (0);
                    486: 
                    487:        if (source->bad)
                    488:                return (0);
                    489: 
                    490:        if (!cbs->start_called && cbs->startfunc != NULL) {
                    491:                result = cbs->startfunc(source, cbs->arg, blocking);
                    492:                if (result != ISC_R_SUCCESS)
                    493:                        return (0);
                    494:                cbs->start_called = ISC_TRUE;
                    495:        }
                    496: 
                    497:        added = 0;
                    498:        result = ISC_R_SUCCESS;
                    499:        while (desired > 0 && result == ISC_R_SUCCESS) {
                    500:                result = cbs->getfunc(source, cbs->arg, blocking);
                    501:                if (result == ISC_R_QUEUEFULL) {
                    502:                        got = crunchsamples(ent, &cbs->samplequeue);
                    503:                        added += got;
                    504:                        desired -= ISC_MIN(got, desired);
                    505:                        result = ISC_R_SUCCESS;
                    506:                } else if (result != ISC_R_SUCCESS &&
                    507:                           result != ISC_R_NOTBLOCKING)
                    508:                        source->bad = ISC_TRUE;
                    509: 
                    510:        }
                    511: 
                    512:        return (added);
                    513: }
                    514: 
                    515: /*
                    516:  * Extract some number of bytes from the random pool, decreasing the
                    517:  * estimate of randomness as each byte is extracted.
                    518:  *
                    519:  * Do this by stiring the pool and returning a part of hash as randomness.
                    520:  * Note that no secrets are given away here since parts of the hash are
                    521:  * xored together before returned.
                    522:  *
                    523:  * Honor the request from the caller to only return good data, any data,
                    524:  * etc.
                    525:  */
                    526: isc_result_t
                    527: isc_entropy_getdata(isc_entropy_t *ent, void *data, unsigned int length,
                    528:                    unsigned int *returned, unsigned int flags)
                    529: {
                    530:        unsigned int i;
                    531:        isc_sha1_t hash;
                    532:        unsigned char digest[ISC_SHA1_DIGESTLENGTH];
                    533:        isc_uint32_t remain, deltae, count, total;
                    534:        isc_uint8_t *buf;
                    535:        isc_boolean_t goodonly, partial, blocking;
                    536: 
                    537:        REQUIRE(VALID_ENTROPY(ent));
                    538:        REQUIRE(data != NULL);
                    539:        REQUIRE(length > 0);
                    540: 
                    541:        goodonly = ISC_TF((flags & ISC_ENTROPY_GOODONLY) != 0);
                    542:        partial = ISC_TF((flags & ISC_ENTROPY_PARTIAL) != 0);
                    543:        blocking = ISC_TF((flags & ISC_ENTROPY_BLOCKING) != 0);
                    544: 
                    545:        REQUIRE(!partial || returned != NULL);
                    546: 
                    547:        LOCK(&ent->lock);
                    548: 
                    549:        remain = length;
                    550:        buf = data;
                    551:        total = 0;
                    552:        while (remain != 0) {
                    553:                count = ISC_MIN(remain, RND_ENTROPY_THRESHOLD);
                    554: 
                    555:                /*
                    556:                 * If we are extracting good data only, make certain we
                    557:                 * have enough data in our pool for this pass.  If we don't,
                    558:                 * get some, and fail if we can't, and partial returns
                    559:                 * are not ok.
                    560:                 */
                    561:                if (goodonly) {
                    562:                        unsigned int fillcount;
                    563: 
                    564:                        fillcount = ISC_MAX(remain * 8, count * 8);
                    565: 
                    566:                        /*
                    567:                         * If, however, we have at least THRESHOLD_BITS
                    568:                         * of entropy in the pool, don't block here.  It is
                    569:                         * better to drain the pool once in a while and
                    570:                         * then refill it than it is to constantly keep the
                    571:                         * pool full.
                    572:                         */
                    573:                        if (ent->pool.entropy >= THRESHOLD_BITS)
                    574:                                fillpool(ent, fillcount, ISC_FALSE);
                    575:                        else
                    576:                                fillpool(ent, fillcount, blocking);
                    577: 
                    578:                        /*
                    579:                         * Verify that we got enough entropy to do one
                    580:                         * extraction.  If we didn't, bail.
                    581:                         */
                    582:                        if (ent->pool.entropy < THRESHOLD_BITS) {
                    583:                                if (!partial)
                    584:                                        goto zeroize;
                    585:                                else
                    586:                                        goto partial_output;
                    587:                        }
                    588:                } else {
                    589:                        /*
                    590:                         * If we've extracted half our pool size in bits
                    591:                         * since the last refresh, try to refresh here.
                    592:                         */
                    593:                        if (ent->initialized < THRESHOLD_BITS)
                    594:                                fillpool(ent, THRESHOLD_BITS, blocking);
                    595:                        else
                    596:                                fillpool(ent, 0, ISC_FALSE);
                    597: 
                    598:                        /*
                    599:                         * If we've not initialized with enough good random
                    600:                         * data, seed with our crappy code.
                    601:                         */
                    602:                        if (ent->initialized < THRESHOLD_BITS)
                    603:                                reseed(ent);
                    604:                }
                    605: 
                    606:                isc_sha1_init(&hash);
                    607:                isc_sha1_update(&hash, (void *)(ent->pool.pool),
                    608:                                RND_POOLBYTES);
                    609:                isc_sha1_final(&hash, digest);
                    610: 
                    611:                /*
                    612:                 * Stir the extracted data (all of it) back into the pool.
                    613:                 */
                    614:                entropypool_adddata(ent, digest, ISC_SHA1_DIGESTLENGTH, 0);
                    615: 
                    616:                for (i = 0; i < count; i++)
                    617:                        buf[i] = digest[i] ^ digest[i + RND_ENTROPY_THRESHOLD];
                    618: 
                    619:                buf += count;
                    620:                remain -= count;
                    621: 
                    622:                deltae = count * 8;
                    623:                deltae = ISC_MIN(deltae, ent->pool.entropy);
                    624:                total += deltae;
                    625:                subtract_entropy(ent, deltae);
                    626:                add_pseudo(ent, count * 8);
                    627:        }
                    628: 
                    629:  partial_output:
                    630:        memset(digest, 0, sizeof(digest));
                    631: 
                    632:        if (returned != NULL)
                    633:                *returned = (length - remain);
                    634: 
                    635:        UNLOCK(&ent->lock);
                    636: 
                    637:        return (ISC_R_SUCCESS);
                    638: 
                    639:  zeroize:
                    640:        /* put the entropy we almost extracted back */
                    641:        add_entropy(ent, total);
                    642:        memset(data, 0, length);
                    643:        memset(digest, 0, sizeof(digest));
                    644:        if (returned != NULL)
                    645:                *returned = 0;
                    646: 
                    647:        UNLOCK(&ent->lock);
                    648: 
                    649:        return (ISC_R_NOENTROPY);
                    650: }
                    651: 
                    652: static void
                    653: isc_entropypool_init(isc_entropypool_t *pool) {
                    654:        pool->cursor = RND_POOLWORDS - 1;
                    655:        pool->entropy = 0;
                    656:        pool->pseudo = 0;
                    657:        pool->rotate = 0;
                    658:        memset(pool->pool, 0, RND_POOLBYTES);
                    659: }
                    660: 
                    661: static void
                    662: isc_entropypool_invalidate(isc_entropypool_t *pool) {
                    663:        pool->cursor = 0;
                    664:        pool->entropy = 0;
                    665:        pool->pseudo = 0;
                    666:        pool->rotate = 0;
                    667:        memset(pool->pool, 0, RND_POOLBYTES);
                    668: }
                    669: 
                    670: isc_result_t
                    671: isc_entropy_create(isc_mem_t *mctx, isc_entropy_t **entp) {
                    672:        isc_result_t result;
                    673:        isc_entropy_t *ent;
                    674: 
                    675:        REQUIRE(mctx != NULL);
                    676:        REQUIRE(entp != NULL && *entp == NULL);
                    677: 
                    678:        ent = isc_mem_get(mctx, sizeof(isc_entropy_t));
                    679:        if (ent == NULL)
                    680:                return (ISC_R_NOMEMORY);
                    681: 
                    682:        /*
                    683:         * We need a lock.
                    684:         */
                    685:        result = isc_mutex_init(&ent->lock);
                    686:        if (result != ISC_R_SUCCESS)
                    687:                goto errout;
                    688: 
                    689:        /*
                    690:         * From here down, no failures will/can occur.
                    691:         */
                    692:        ISC_LIST_INIT(ent->sources);
                    693:        ent->nextsource = NULL;
                    694:        ent->nsources = 0;
                    695:        ent->mctx = NULL;
                    696:        isc_mem_attach(mctx, &ent->mctx);
                    697:        ent->refcnt = 1;
                    698:        ent->initialized = 0;
                    699:        ent->initcount = 0;
                    700:        ent->magic = ENTROPY_MAGIC;
                    701: 
                    702:        isc_entropypool_init(&ent->pool);
                    703: 
                    704:        *entp = ent;
                    705:        return (ISC_R_SUCCESS);
                    706: 
                    707:  errout:
                    708:        isc_mem_put(mctx, ent, sizeof(isc_entropy_t));
                    709: 
                    710:        return (result);
                    711: }
                    712: 
                    713: /*!
                    714:  * Requires "ent" be locked.
                    715:  */
                    716: static void
                    717: destroysource(isc_entropysource_t **sourcep) {
                    718:        isc_entropysource_t *source;
                    719:        isc_entropy_t *ent;
                    720:        isc_cbsource_t *cbs;
                    721: 
                    722:        source = *sourcep;
                    723:        *sourcep = NULL;
                    724:        ent = source->ent;
                    725: 
                    726:        ISC_LIST_UNLINK(ent->sources, source, link);
                    727:        ent->nextsource = NULL;
                    728:        REQUIRE(ent->nsources > 0);
                    729:        ent->nsources--;
                    730: 
                    731:        switch (source->type) {
                    732:        case ENTROPY_SOURCETYPE_FILE:
                    733:                if (! source->bad)
                    734:                        destroyfilesource(&source->sources.file);
                    735:                break;
                    736:        case ENTROPY_SOURCETYPE_USOCKET:
                    737:                if (! source->bad)
                    738:                        destroyusocketsource(&source->sources.usocket);
                    739:                break;
                    740:        case ENTROPY_SOURCETYPE_SAMPLE:
                    741:                samplequeue_release(ent, &source->sources.sample.samplequeue);
                    742:                break;
                    743:        case ENTROPY_SOURCETYPE_CALLBACK:
                    744:                cbs = &source->sources.callback;
                    745:                if (cbs->start_called && cbs->stopfunc != NULL) {
                    746:                        cbs->stopfunc(source, cbs->arg);
                    747:                        cbs->start_called = ISC_FALSE;
                    748:                }
                    749:                samplequeue_release(ent, &cbs->samplequeue);
                    750:                break;
                    751:        }
                    752: 
                    753:        memset(source, 0, sizeof(isc_entropysource_t));
                    754: 
                    755:        isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
                    756: }
                    757: 
                    758: static inline isc_boolean_t
                    759: destroy_check(isc_entropy_t *ent) {
                    760:        isc_entropysource_t *source;
                    761: 
                    762:        if (ent->refcnt > 0)
                    763:                return (ISC_FALSE);
                    764: 
                    765:        source = ISC_LIST_HEAD(ent->sources);
                    766:        while (source != NULL) {
                    767:                switch (source->type) {
                    768:                case ENTROPY_SOURCETYPE_FILE:
                    769:                case ENTROPY_SOURCETYPE_USOCKET:
                    770:                        break;
                    771:                default:
                    772:                        return (ISC_FALSE);
                    773:                }
                    774:                source = ISC_LIST_NEXT(source, link);
                    775:        }
                    776: 
                    777:        return (ISC_TRUE);
                    778: }
                    779: 
                    780: static void
                    781: destroy(isc_entropy_t **entp) {
                    782:        isc_entropy_t *ent;
                    783:        isc_entropysource_t *source;
                    784:        isc_mem_t *mctx;
                    785: 
                    786:        REQUIRE(entp != NULL && *entp != NULL);
                    787:        ent = *entp;
                    788:        *entp = NULL;
                    789: 
                    790:        LOCK(&ent->lock);
                    791: 
                    792:        REQUIRE(ent->refcnt == 0);
                    793: 
                    794:        /*
                    795:         * Here, detach non-sample sources.
                    796:         */
                    797:        source = ISC_LIST_HEAD(ent->sources);
                    798:        while (source != NULL) {
                    799:                switch(source->type) {
                    800:                case ENTROPY_SOURCETYPE_FILE:
                    801:                case ENTROPY_SOURCETYPE_USOCKET:
                    802:                        destroysource(&source);
                    803:                        break;
                    804:                }
                    805:                source = ISC_LIST_HEAD(ent->sources);
                    806:        }
                    807: 
                    808:        /*
                    809:         * If there are other types of sources, we've found a bug.
                    810:         */
                    811:        REQUIRE(ISC_LIST_EMPTY(ent->sources));
                    812: 
                    813:        mctx = ent->mctx;
                    814: 
                    815:        isc_entropypool_invalidate(&ent->pool);
                    816: 
                    817:        UNLOCK(&ent->lock);
                    818: 
                    819:        DESTROYLOCK(&ent->lock);
                    820: 
                    821:        memset(ent, 0, sizeof(isc_entropy_t));
                    822:        isc_mem_put(mctx, ent, sizeof(isc_entropy_t));
                    823:        isc_mem_detach(&mctx);
                    824: }
                    825: 
                    826: void
                    827: isc_entropy_destroysource(isc_entropysource_t **sourcep) {
                    828:        isc_entropysource_t *source;
                    829:        isc_entropy_t *ent;
                    830:        isc_boolean_t killit;
                    831: 
                    832:        REQUIRE(sourcep != NULL);
                    833:        REQUIRE(VALID_SOURCE(*sourcep));
                    834: 
                    835:        source = *sourcep;
                    836:        *sourcep = NULL;
                    837: 
                    838:        ent = source->ent;
                    839:        REQUIRE(VALID_ENTROPY(ent));
                    840: 
                    841:        LOCK(&ent->lock);
                    842: 
                    843:        destroysource(&source);
                    844: 
                    845:        killit = destroy_check(ent);
                    846: 
                    847:        UNLOCK(&ent->lock);
                    848: 
                    849:        if (killit)
                    850:                destroy(&ent);
                    851: }
                    852: 
                    853: isc_result_t
                    854: isc_entropy_createcallbacksource(isc_entropy_t *ent,
                    855:                                 isc_entropystart_t start,
                    856:                                 isc_entropyget_t get,
                    857:                                 isc_entropystop_t stop,
                    858:                                 void *arg,
                    859:                                 isc_entropysource_t **sourcep)
                    860: {
                    861:        isc_result_t result;
                    862:        isc_entropysource_t *source;
                    863:        isc_cbsource_t *cbs;
                    864: 
                    865:        REQUIRE(VALID_ENTROPY(ent));
                    866:        REQUIRE(get != NULL);
                    867:        REQUIRE(sourcep != NULL && *sourcep == NULL);
                    868: 
                    869:        LOCK(&ent->lock);
                    870: 
                    871:        source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
                    872:        if (source == NULL) {
                    873:                result = ISC_R_NOMEMORY;
                    874:                goto errout;
                    875:        }
                    876:        source->bad = ISC_FALSE;
                    877: 
                    878:        cbs = &source->sources.callback;
                    879: 
                    880:        result = samplesource_allocate(ent, &cbs->samplequeue);
                    881:        if (result != ISC_R_SUCCESS)
                    882:                goto errout;
                    883: 
                    884:        cbs->start_called = ISC_FALSE;
                    885:        cbs->startfunc = start;
                    886:        cbs->getfunc = get;
                    887:        cbs->stopfunc = stop;
                    888:        cbs->arg = arg;
                    889: 
                    890:        /*
                    891:         * From here down, no failures can occur.
                    892:         */
                    893:        source->magic = SOURCE_MAGIC;
                    894:        source->type = ENTROPY_SOURCETYPE_CALLBACK;
                    895:        source->ent = ent;
                    896:        source->total = 0;
                    897:        memset(source->name, 0, sizeof(source->name));
                    898:        ISC_LINK_INIT(source, link);
                    899: 
                    900:        /*
                    901:         * Hook it into the entropy system.
                    902:         */
                    903:        ISC_LIST_APPEND(ent->sources, source, link);
                    904:        ent->nsources++;
                    905: 
                    906:        *sourcep = source;
                    907: 
                    908:        UNLOCK(&ent->lock);
                    909:        return (ISC_R_SUCCESS);
                    910: 
                    911:  errout:
                    912:        if (source != NULL)
                    913:                isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
                    914: 
                    915:        UNLOCK(&ent->lock);
                    916: 
                    917:        return (result);
                    918: }
                    919: 
                    920: void
                    921: isc_entropy_stopcallbacksources(isc_entropy_t *ent) {
                    922:        isc_entropysource_t *source;
                    923:        isc_cbsource_t *cbs;
                    924: 
                    925:        REQUIRE(VALID_ENTROPY(ent));
                    926: 
                    927:        LOCK(&ent->lock);
                    928: 
                    929:        source = ISC_LIST_HEAD(ent->sources);
                    930:        while (source != NULL) {
                    931:                if (source->type == ENTROPY_SOURCETYPE_CALLBACK) {
                    932:                        cbs = &source->sources.callback;
                    933:                        if (cbs->start_called && cbs->stopfunc != NULL) {
                    934:                                cbs->stopfunc(source, cbs->arg);
                    935:                                cbs->start_called = ISC_FALSE;
                    936:                        }
                    937:                }
                    938: 
                    939:                source = ISC_LIST_NEXT(source, link);
                    940:        }
                    941: 
                    942:        UNLOCK(&ent->lock);
                    943: }
                    944: 
                    945: isc_result_t
                    946: isc_entropy_createsamplesource(isc_entropy_t *ent,
                    947:                               isc_entropysource_t **sourcep)
                    948: {
                    949:        isc_result_t result;
                    950:        isc_entropysource_t *source;
                    951:        sample_queue_t *sq;
                    952: 
                    953:        REQUIRE(VALID_ENTROPY(ent));
                    954:        REQUIRE(sourcep != NULL && *sourcep == NULL);
                    955: 
                    956:        LOCK(&ent->lock);
                    957: 
                    958:        source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
                    959:        if (source == NULL) {
                    960:                result = ISC_R_NOMEMORY;
                    961:                goto errout;
                    962:        }
                    963: 
                    964:        sq = &source->sources.sample.samplequeue;
                    965:        result = samplesource_allocate(ent, sq);
                    966:        if (result != ISC_R_SUCCESS)
                    967:                goto errout;
                    968: 
                    969:        /*
                    970:         * From here down, no failures can occur.
                    971:         */
                    972:        source->magic = SOURCE_MAGIC;
                    973:        source->type = ENTROPY_SOURCETYPE_SAMPLE;
                    974:        source->ent = ent;
                    975:        source->total = 0;
                    976:        memset(source->name, 0, sizeof(source->name));
                    977:        ISC_LINK_INIT(source, link);
                    978: 
                    979:        /*
                    980:         * Hook it into the entropy system.
                    981:         */
                    982:        ISC_LIST_APPEND(ent->sources, source, link);
                    983:        ent->nsources++;
                    984: 
                    985:        *sourcep = source;
                    986: 
                    987:        UNLOCK(&ent->lock);
                    988:        return (ISC_R_SUCCESS);
                    989: 
                    990:  errout:
                    991:        if (source != NULL)
                    992:                isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
                    993: 
                    994:        UNLOCK(&ent->lock);
                    995: 
                    996:        return (result);
                    997: }
                    998: 
                    999: /*!
                   1000:  * Add a sample, and return ISC_R_SUCCESS if the queue has become full,
                   1001:  * ISC_R_NOENTROPY if it has space remaining, and ISC_R_NOMORE if the
                   1002:  * queue was full when this function was called.
                   1003:  */
                   1004: static isc_result_t
                   1005: addsample(sample_queue_t *sq, isc_uint32_t sample, isc_uint32_t extra) {
                   1006:        if (sq->nsamples >= RND_EVENTQSIZE)
                   1007:                return (ISC_R_NOMORE);
                   1008: 
                   1009:        sq->samples[sq->nsamples] = sample;
                   1010:        sq->extra[sq->nsamples] = extra;
                   1011:        sq->nsamples++;
                   1012: 
                   1013:        if (sq->nsamples >= RND_EVENTQSIZE)
                   1014:                return (ISC_R_QUEUEFULL);
                   1015: 
                   1016:        return (ISC_R_SUCCESS);
                   1017: }
                   1018: 
                   1019: isc_result_t
                   1020: isc_entropy_addsample(isc_entropysource_t *source, isc_uint32_t sample,
                   1021:                      isc_uint32_t extra)
                   1022: {
                   1023:        isc_entropy_t *ent;
                   1024:        sample_queue_t *sq;
                   1025:        unsigned int entropy;
                   1026:        isc_result_t result;
                   1027: 
                   1028:        REQUIRE(VALID_SOURCE(source));
                   1029: 
                   1030:        ent = source->ent;
                   1031: 
                   1032:        LOCK(&ent->lock);
                   1033: 
                   1034:        sq = &source->sources.sample.samplequeue;
                   1035:        result = addsample(sq, sample, extra);
                   1036:        if (result == ISC_R_QUEUEFULL) {
                   1037:                entropy = crunchsamples(ent, sq);
                   1038:                add_entropy(ent, entropy);
                   1039:        }
                   1040: 
                   1041:        UNLOCK(&ent->lock);
                   1042: 
                   1043:        return (result);
                   1044: }
                   1045: 
                   1046: isc_result_t
                   1047: isc_entropy_addcallbacksample(isc_entropysource_t *source, isc_uint32_t sample,
                   1048:                              isc_uint32_t extra)
                   1049: {
                   1050:        sample_queue_t *sq;
                   1051:        isc_result_t result;
                   1052: 
                   1053:        REQUIRE(VALID_SOURCE(source));
                   1054:        REQUIRE(source->type == ENTROPY_SOURCETYPE_CALLBACK);
                   1055: 
                   1056:        sq = &source->sources.callback.samplequeue;
                   1057:        result = addsample(sq, sample, extra);
                   1058: 
                   1059:        return (result);
                   1060: }
                   1061: 
                   1062: void
                   1063: isc_entropy_putdata(isc_entropy_t *ent, void *data, unsigned int length,
                   1064:                    isc_uint32_t entropy)
                   1065: {
                   1066:        REQUIRE(VALID_ENTROPY(ent));
                   1067: 
                   1068:        LOCK(&ent->lock);
                   1069: 
                   1070:        entropypool_adddata(ent, data, length, entropy);
                   1071: 
                   1072:        if (ent->initialized < THRESHOLD_BITS)
                   1073:                ent->initialized = THRESHOLD_BITS;
                   1074: 
                   1075:        UNLOCK(&ent->lock);
                   1076: }
                   1077: 
                   1078: static void
                   1079: dumpstats(isc_entropy_t *ent, FILE *out) {
                   1080:        fprintf(out,
                   1081:                isc_msgcat_get(isc_msgcat, ISC_MSGSET_ENTROPY,
                   1082:                               ISC_MSG_ENTROPYSTATS,
                   1083:                               "Entropy pool %p:  refcnt %u cursor %u,"
                   1084:                               " rotate %u entropy %u pseudo %u nsources %u"
                   1085:                               " nextsource %p initialized %u initcount %u\n"),
                   1086:                ent, ent->refcnt,
                   1087:                ent->pool.cursor, ent->pool.rotate,
                   1088:                ent->pool.entropy, ent->pool.pseudo,
                   1089:                ent->nsources, ent->nextsource, ent->initialized,
                   1090:                ent->initcount);
                   1091: }
                   1092: 
                   1093: /*
                   1094:  * This function ignores locking.  Use at your own risk.
                   1095:  */
                   1096: void
                   1097: isc_entropy_stats(isc_entropy_t *ent, FILE *out) {
                   1098:        REQUIRE(VALID_ENTROPY(ent));
                   1099: 
                   1100:        LOCK(&ent->lock);
                   1101:        dumpstats(ent, out);
                   1102:        UNLOCK(&ent->lock);
                   1103: }
                   1104: 
                   1105: unsigned int
                   1106: isc_entropy_status(isc_entropy_t *ent) {
                   1107:        unsigned int estimate;
                   1108: 
                   1109:        LOCK(&ent->lock);
                   1110:        estimate = ent->pool.entropy;
                   1111:        UNLOCK(&ent->lock);
                   1112: 
                   1113:        return estimate;
                   1114: }
                   1115: 
                   1116: void
                   1117: isc_entropy_attach(isc_entropy_t *ent, isc_entropy_t **entp) {
                   1118:        REQUIRE(VALID_ENTROPY(ent));
                   1119:        REQUIRE(entp != NULL && *entp == NULL);
                   1120: 
                   1121:        LOCK(&ent->lock);
                   1122: 
                   1123:        ent->refcnt++;
                   1124:        *entp = ent;
                   1125: 
                   1126:        UNLOCK(&ent->lock);
                   1127: }
                   1128: 
                   1129: void
                   1130: isc_entropy_detach(isc_entropy_t **entp) {
                   1131:        isc_entropy_t *ent;
                   1132:        isc_boolean_t killit;
                   1133: 
                   1134:        REQUIRE(entp != NULL && VALID_ENTROPY(*entp));
                   1135:        ent = *entp;
                   1136:        *entp = NULL;
                   1137: 
                   1138:        LOCK(&ent->lock);
                   1139: 
                   1140:        REQUIRE(ent->refcnt > 0);
                   1141:        ent->refcnt--;
                   1142: 
                   1143:        killit = destroy_check(ent);
                   1144: 
                   1145:        UNLOCK(&ent->lock);
                   1146: 
                   1147:        if (killit)
                   1148:                destroy(&ent);
                   1149: }
                   1150: 
                   1151: static isc_result_t
                   1152: kbdstart(isc_entropysource_t *source, void *arg, isc_boolean_t blocking) {
                   1153:        /*
                   1154:         * The intent of "first" is to provide a warning message only once
                   1155:         * during the run of a program that might try to gather keyboard
                   1156:         * entropy multiple times.
                   1157:         */
                   1158:        static isc_boolean_t first = ISC_TRUE;
                   1159: 
                   1160:        UNUSED(arg);
                   1161: 
                   1162:        if (! blocking)
                   1163:                return (ISC_R_NOENTROPY);
                   1164: 
                   1165:        if (first) {
                   1166:                if (source->warn_keyboard)
                   1167:                        fprintf(stderr, "You must use the keyboard to create "
                   1168:                                "entropy, since your system is lacking\n"
                   1169:                                "/dev/random (or equivalent)\n\n");
                   1170:                first = ISC_FALSE;
                   1171:        }
                   1172:        fprintf(stderr, "start typing:\n");
                   1173: 
                   1174:        return (isc_keyboard_open(&source->kbd));
                   1175: }
                   1176: 
                   1177: static void
                   1178: kbdstop(isc_entropysource_t *source, void *arg) {
                   1179: 
                   1180:        UNUSED(arg);
                   1181: 
                   1182:        if (! isc_keyboard_canceled(&source->kbd))
                   1183:                fprintf(stderr, "stop typing.\r\n");
                   1184: 
                   1185:        (void)isc_keyboard_close(&source->kbd, 3);
                   1186: }
                   1187: 
                   1188: static isc_result_t
                   1189: kbdget(isc_entropysource_t *source, void *arg, isc_boolean_t blocking) {
                   1190:        isc_result_t result;
                   1191:        isc_time_t t;
                   1192:        isc_uint32_t sample;
                   1193:        isc_uint32_t extra;
                   1194:        unsigned char c;
                   1195: 
                   1196:        UNUSED(arg);
                   1197: 
                   1198:        if (!blocking)
                   1199:                return (ISC_R_NOTBLOCKING);
                   1200: 
                   1201:        result = isc_keyboard_getchar(&source->kbd, &c);
                   1202:        if (result != ISC_R_SUCCESS)
                   1203:                return (result);
                   1204: 
                   1205:        TIME_NOW(&t);
                   1206: 
                   1207:        sample = isc_time_nanoseconds(&t);
                   1208:        extra = c;
                   1209: 
                   1210:        result = isc_entropy_addcallbacksample(source, sample, extra);
                   1211:        if (result != ISC_R_SUCCESS) {
                   1212:                fprintf(stderr, "\r\n");
                   1213:                return (result);
                   1214:        }
                   1215: 
                   1216:        fprintf(stderr, ".");
                   1217:        fflush(stderr);
                   1218: 
                   1219:        return (result);
                   1220: }
                   1221: 
                   1222: isc_result_t
                   1223: isc_entropy_usebestsource(isc_entropy_t *ectx, isc_entropysource_t **source,
                   1224:                          const char *randomfile, int use_keyboard)
                   1225: {
                   1226:        isc_result_t result;
                   1227:        isc_result_t final_result = ISC_R_NOENTROPY;
                   1228:        isc_boolean_t userfile = ISC_TRUE;
                   1229: 
                   1230:        REQUIRE(VALID_ENTROPY(ectx));
                   1231:        REQUIRE(source != NULL && *source == NULL);
                   1232:        REQUIRE(use_keyboard == ISC_ENTROPY_KEYBOARDYES ||
                   1233:                use_keyboard == ISC_ENTROPY_KEYBOARDNO  ||
                   1234:                use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE);
                   1235: 
                   1236: #ifdef PATH_RANDOMDEV
                   1237:        if (randomfile == NULL) {
                   1238:                randomfile = PATH_RANDOMDEV;
                   1239:                userfile = ISC_FALSE;
                   1240:        }
                   1241: #endif
                   1242: 
                   1243:        if (randomfile != NULL && use_keyboard != ISC_ENTROPY_KEYBOARDYES) {
                   1244:                result = isc_entropy_createfilesource(ectx, randomfile);
                   1245:                if (result == ISC_R_SUCCESS &&
                   1246:                    use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE)
                   1247:                        use_keyboard = ISC_ENTROPY_KEYBOARDNO;
                   1248:                if (result != ISC_R_SUCCESS && userfile)
                   1249:                        return (result);
                   1250: 
                   1251:                final_result = result;
                   1252:        }
                   1253: 
                   1254:        if (use_keyboard != ISC_ENTROPY_KEYBOARDNO) {
                   1255:                result = isc_entropy_createcallbacksource(ectx, kbdstart,
                   1256:                                                          kbdget, kbdstop,
                   1257:                                                          NULL, source);
                   1258:                if (result == ISC_R_SUCCESS)
                   1259:                        (*source)->warn_keyboard =
                   1260:                                ISC_TF(use_keyboard ==
                   1261:                                       ISC_ENTROPY_KEYBOARDMAYBE);
                   1262: 
                   1263:                if (final_result != ISC_R_SUCCESS)
                   1264:                        final_result = result;
                   1265:        }
                   1266: 
                   1267:        /*
                   1268:         * final_result is ISC_R_SUCCESS if at least one source of entropy
                   1269:         * could be started, otherwise it is the error from the most recently
                   1270:         * failed operation (or ISC_R_NOENTROPY if PATH_RANDOMDEV is not
                   1271:         * defined and use_keyboard is ISC_ENTROPY_KEYBOARDNO).
                   1272:         */
                   1273:        return (final_result);
                   1274: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>