Annotation of embedaddon/ntp/lib/isc/entropy.c, revision 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>