Annotation of embedaddon/strongswan/src/libstrongswan/utils/chunk.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2008-2019 Tobias Brunner
        !             3:  * Copyright (C) 2005-2006 Martin Willi
        !             4:  * Copyright (C) 2005 Jan Hutter
        !             5:  * HSR Hochschule fuer Technik Rapperswil
        !             6:  *
        !             7:  * This program is free software; you can redistribute it and/or modify it
        !             8:  * under the terms of the GNU General Public License as published by the
        !             9:  * Free Software Foundation; either version 2 of the License, or (at your
        !            10:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !            11:  *
        !            12:  * This program is distributed in the hope that it will be useful, but
        !            13:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            14:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            15:  * for more details.
        !            16:  */
        !            17: 
        !            18: #include <stdio.h>
        !            19: #include <sys/types.h>
        !            20: #include <sys/stat.h>
        !            21: #ifdef HAVE_MMAP
        !            22: # include <sys/mman.h>
        !            23: #endif
        !            24: #include <fcntl.h>
        !            25: #include <unistd.h>
        !            26: #include <errno.h>
        !            27: #include <ctype.h>
        !            28: #include <time.h>
        !            29: 
        !            30: #include "chunk.h"
        !            31: 
        !            32: /**
        !            33:  * Empty chunk.
        !            34:  */
        !            35: chunk_t chunk_empty = { NULL, 0 };
        !            36: 
        !            37: /**
        !            38:  * Described in header.
        !            39:  */
        !            40: chunk_t chunk_create_clone(u_char *ptr, chunk_t chunk)
        !            41: {
        !            42:        chunk_t clone = chunk_empty;
        !            43: 
        !            44:        if (chunk.ptr && chunk.len > 0)
        !            45:        {
        !            46:                clone.ptr = ptr;
        !            47:                clone.len = chunk.len;
        !            48:                memcpy(clone.ptr, chunk.ptr, chunk.len);
        !            49:        }
        !            50: 
        !            51:        return clone;
        !            52: }
        !            53: 
        !            54: /**
        !            55:  * Described in header.
        !            56:  */
        !            57: size_t chunk_length(const char* mode, ...)
        !            58: {
        !            59:        va_list chunks;
        !            60:        size_t length = 0;
        !            61: 
        !            62:        va_start(chunks, mode);
        !            63:        while (TRUE)
        !            64:        {
        !            65:                switch (*mode++)
        !            66:                {
        !            67:                        case 'm':
        !            68:                        case 'c':
        !            69:                        case 's':
        !            70:                        {
        !            71:                                chunk_t ch = va_arg(chunks, chunk_t);
        !            72:                                length += ch.len;
        !            73:                                continue;
        !            74:                        }
        !            75:                        default:
        !            76:                                break;
        !            77:                }
        !            78:                break;
        !            79:        }
        !            80:        va_end(chunks);
        !            81:        return length;
        !            82: }
        !            83: 
        !            84: /**
        !            85:  * Described in header.
        !            86:  */
        !            87: chunk_t chunk_create_cat(u_char *ptr, const char* mode, ...)
        !            88: {
        !            89:        va_list chunks;
        !            90:        chunk_t construct = chunk_create(ptr, 0);
        !            91: 
        !            92:        va_start(chunks, mode);
        !            93:        while (TRUE)
        !            94:        {
        !            95:                bool free_chunk = FALSE, clear_chunk = FALSE;
        !            96:                chunk_t ch;
        !            97: 
        !            98:                switch (*mode++)
        !            99:                {
        !           100:                        case 's':
        !           101:                                clear_chunk = TRUE;
        !           102:                                /* FALL */
        !           103:                        case 'm':
        !           104:                                free_chunk = TRUE;
        !           105:                                /* FALL */
        !           106:                        case 'c':
        !           107:                                ch = va_arg(chunks, chunk_t);
        !           108:                                memcpy(ptr, ch.ptr, ch.len);
        !           109:                                ptr += ch.len;
        !           110:                                construct.len += ch.len;
        !           111:                                if (clear_chunk)
        !           112:                                {
        !           113:                                        chunk_clear(&ch);
        !           114:                                }
        !           115:                                else if (free_chunk)
        !           116:                                {
        !           117:                                        free(ch.ptr);
        !           118:                                }
        !           119:                                continue;
        !           120:                        default:
        !           121:                                break;
        !           122:                }
        !           123:                break;
        !           124:        }
        !           125:        va_end(chunks);
        !           126: 
        !           127:        return construct;
        !           128: }
        !           129: 
        !           130: /**
        !           131:  * Described in header.
        !           132:  */
        !           133: void chunk_split(chunk_t chunk, const char *mode, ...)
        !           134: {
        !           135:        va_list chunks;
        !           136:        u_int len;
        !           137:        chunk_t *ch;
        !           138: 
        !           139:        va_start(chunks, mode);
        !           140:        while (TRUE)
        !           141:        {
        !           142:                if (*mode == '\0')
        !           143:                {
        !           144:                        break;
        !           145:                }
        !           146:                len = va_arg(chunks, u_int);
        !           147:                ch = va_arg(chunks, chunk_t*);
        !           148:                /* a null chunk means skip len bytes */
        !           149:                if (ch == NULL)
        !           150:                {
        !           151:                        chunk = chunk_skip(chunk, len);
        !           152:                        continue;
        !           153:                }
        !           154:                switch (*mode++)
        !           155:                {
        !           156:                        case 'm':
        !           157:                        {
        !           158:                                ch->len = min(chunk.len, len);
        !           159:                                if (ch->len)
        !           160:                                {
        !           161:                                        ch->ptr = chunk.ptr;
        !           162:                                }
        !           163:                                else
        !           164:                                {
        !           165:                                        ch->ptr = NULL;
        !           166:                                }
        !           167:                                chunk = chunk_skip(chunk, ch->len);
        !           168:                                continue;
        !           169:                        }
        !           170:                        case 'a':
        !           171:                        {
        !           172:                                ch->len = min(chunk.len, len);
        !           173:                                if (ch->len)
        !           174:                                {
        !           175:                                        ch->ptr = malloc(ch->len);
        !           176:                                        memcpy(ch->ptr, chunk.ptr, ch->len);
        !           177:                                }
        !           178:                                else
        !           179:                                {
        !           180:                                        ch->ptr = NULL;
        !           181:                                }
        !           182:                                chunk = chunk_skip(chunk, ch->len);
        !           183:                                continue;
        !           184:                        }
        !           185:                        case 'c':
        !           186:                        {
        !           187:                                ch->len = min(ch->len, chunk.len);
        !           188:                                ch->len = min(ch->len, len);
        !           189:                                if (ch->len)
        !           190:                                {
        !           191:                                        memcpy(ch->ptr, chunk.ptr, ch->len);
        !           192:                                }
        !           193:                                else
        !           194:                                {
        !           195:                                        ch->ptr = NULL;
        !           196:                                }
        !           197:                                chunk = chunk_skip(chunk, ch->len);
        !           198:                                continue;
        !           199:                        }
        !           200:                        default:
        !           201:                                break;
        !           202:                }
        !           203:                break;
        !           204:        }
        !           205:        va_end(chunks);
        !           206: }
        !           207: 
        !           208: /**
        !           209:  * Described in header.
        !           210:  */
        !           211: bool chunk_write(chunk_t chunk, char *path, mode_t mask, bool force)
        !           212: {
        !           213:        mode_t oldmask;
        !           214:        FILE *fd;
        !           215:        bool good = FALSE;
        !           216:        int tmp = 0;
        !           217: 
        !           218:        if (!force && access(path, F_OK) == 0)
        !           219:        {
        !           220:                errno = EEXIST;
        !           221:                return FALSE;
        !           222:        }
        !           223:        oldmask = umask(mask);
        !           224:        fd = fopen(path,
        !           225: #ifdef WIN32
        !           226:                                "wb"
        !           227: #else
        !           228:                                "w"
        !           229: #endif
        !           230:        );
        !           231: 
        !           232:        if (fd)
        !           233:        {
        !           234:                if (fwrite(chunk.ptr, sizeof(u_char), chunk.len, fd) == chunk.len)
        !           235:                {
        !           236:                        good = TRUE;
        !           237:                }
        !           238:                else
        !           239:                {
        !           240:                        tmp = errno;
        !           241:                }
        !           242:                fclose(fd);
        !           243:        }
        !           244:        else
        !           245:        {
        !           246:                tmp = errno;
        !           247:        }
        !           248:        umask(oldmask);
        !           249:        errno = tmp;
        !           250:        return good;
        !           251: }
        !           252: 
        !           253: /**
        !           254:  * Described in header.
        !           255:  */
        !           256: bool chunk_from_fd(int fd, chunk_t *out)
        !           257: {
        !           258:        struct stat sb;
        !           259:        char *buf, *tmp;
        !           260:        ssize_t len, total = 0, bufsize;
        !           261: 
        !           262:        if (fstat(fd, &sb) == 0 && S_ISREG(sb.st_mode))
        !           263:        {
        !           264:                bufsize = sb.st_size;
        !           265:        }
        !           266:        else
        !           267:        {
        !           268:                bufsize = 256;
        !           269:        }
        !           270:        buf = malloc(bufsize);
        !           271:        if (!buf)
        !           272:        {       /* for huge files */
        !           273:                return FALSE;
        !           274:        }
        !           275: 
        !           276:        while (TRUE)
        !           277:        {
        !           278:                len = read(fd, buf + total, bufsize - total);
        !           279: #ifdef WIN32
        !           280:                if (len == -1 && errno == EBADF)
        !           281:                {       /* operating on a Winsock socket? */
        !           282:                        len = recv(fd, buf + total, bufsize - total, 0);
        !           283:                }
        !           284: #endif
        !           285:                if (len < 0)
        !           286:                {
        !           287:                        free(buf);
        !           288:                        return FALSE;
        !           289:                }
        !           290:                if (len == 0)
        !           291:                {
        !           292:                        break;
        !           293:                }
        !           294:                total += len;
        !           295:                if (total == bufsize)
        !           296:                {
        !           297:                        bufsize *= 2;
        !           298:                        tmp = realloc(buf, bufsize);
        !           299:                        if (!tmp)
        !           300:                        {
        !           301:                                free(buf);
        !           302:                                return FALSE;
        !           303:                        }
        !           304:                        buf = tmp;
        !           305:                }
        !           306:        }
        !           307:        if (total == 0)
        !           308:        {
        !           309:                free(buf);
        !           310:                buf = NULL;
        !           311:        }
        !           312:        else if (total < bufsize)
        !           313:        {
        !           314:                buf = realloc(buf, total);
        !           315:        }
        !           316:        *out = chunk_create(buf, total);
        !           317:        return TRUE;
        !           318: }
        !           319: 
        !           320: /**
        !           321:  * Implementation for mmap()ed chunks
        !           322:  */
        !           323: typedef struct {
        !           324:        /* public chunk interface */
        !           325:        chunk_t public;
        !           326:        /* FD of open file */
        !           327:        int fd;
        !           328:        /* mmap() address */
        !           329:        void *map;
        !           330:        /* size of map */
        !           331:        size_t len;
        !           332:        /* do we write? */
        !           333:        bool wr;
        !           334: } mmaped_chunk_t;
        !           335: 
        !           336: /**
        !           337:  * See header.
        !           338:  */
        !           339: chunk_t *chunk_map(char *path, bool wr)
        !           340: {
        !           341:        mmaped_chunk_t *chunk;
        !           342:        struct stat sb;
        !           343:        int tmp, flags;
        !           344: 
        !           345:        flags = wr ? O_RDWR : O_RDONLY;
        !           346: #ifdef WIN32
        !           347:        flags |= O_BINARY;
        !           348: #endif
        !           349: 
        !           350:        INIT(chunk,
        !           351:                .fd = open(path, flags),
        !           352:                .wr = wr,
        !           353:        );
        !           354: 
        !           355:        if (chunk->fd == -1)
        !           356:        {
        !           357:                free(chunk);
        !           358:                return NULL;
        !           359:        }
        !           360:        if (fstat(chunk->fd, &sb) == -1)
        !           361:        {
        !           362:                tmp = errno;
        !           363:                chunk_unmap(&chunk->public);
        !           364:                errno = tmp;
        !           365:                return NULL;
        !           366:        }
        !           367: #ifdef HAVE_MMAP
        !           368:        chunk->len = sb.st_size;
        !           369:        /* map non-empty files only, as mmap() complains otherwise */
        !           370:        if (chunk->len)
        !           371:        {
        !           372:                /* in read-only mode, we allow writes, but don't sync to disk */
        !           373:                chunk->map = mmap(NULL, chunk->len, PROT_READ | PROT_WRITE,
        !           374:                                                  wr ? MAP_SHARED : MAP_PRIVATE, chunk->fd, 0);
        !           375:                if (chunk->map == MAP_FAILED)
        !           376:                {
        !           377:                        tmp = errno;
        !           378:                        chunk_unmap(&chunk->public);
        !           379:                        errno = tmp;
        !           380:                        return NULL;
        !           381:                }
        !           382:        }
        !           383:        chunk->public = chunk_create(chunk->map, chunk->len);
        !           384: #else /* !HAVE_MMAP */
        !           385:        if (!chunk_from_fd(chunk->fd, &chunk->public))
        !           386:        {
        !           387:                tmp = errno;
        !           388:                chunk_unmap(&chunk->public);
        !           389:                errno = tmp;
        !           390:                return NULL;
        !           391:        }
        !           392:        chunk->map = chunk->public.ptr;
        !           393:        chunk->len = chunk->public.len;
        !           394: #endif /* !HAVE_MMAP */
        !           395:        return &chunk->public;
        !           396: }
        !           397: 
        !           398: /**
        !           399:  * See header.
        !           400:  */
        !           401: bool chunk_unmap(chunk_t *public)
        !           402: {
        !           403:        mmaped_chunk_t *chunk;
        !           404:        bool ret = FALSE;
        !           405:        int tmp = 0;
        !           406: 
        !           407:        chunk = (mmaped_chunk_t*)public;
        !           408: #ifdef HAVE_MMAP
        !           409:        if (chunk->map && chunk->map != MAP_FAILED)
        !           410:        {
        !           411:                ret = munmap(chunk->map, chunk->len) == 0;
        !           412:                tmp = errno;
        !           413:        }
        !           414: #else /* !HAVE_MMAP */
        !           415:        if (chunk->wr)
        !           416:        {
        !           417:                if (lseek(chunk->fd, 0, SEEK_SET) != -1)
        !           418:                {
        !           419:                        int len, total = 0;
        !           420: 
        !           421:                        ret = TRUE;
        !           422:                        while (total < chunk->len)
        !           423:                        {
        !           424:                                len = write(chunk->fd, chunk->map + total, chunk->len - total);
        !           425:                                if (len <= 0)
        !           426:                                {
        !           427:                                        ret = FALSE;
        !           428:                                        break;
        !           429:                                }
        !           430:                                total += len;
        !           431:                        }
        !           432:                }
        !           433:                tmp = errno;
        !           434:        }
        !           435:        else
        !           436:        {
        !           437:                ret = TRUE;
        !           438:        }
        !           439:        free(chunk->map);
        !           440: #endif /* !HAVE_MMAP */
        !           441:        close(chunk->fd);
        !           442:        free(chunk);
        !           443:        errno = tmp;
        !           444: 
        !           445:        return ret;
        !           446: }
        !           447: 
        !           448: /** hex conversion digits */
        !           449: static char hexdig_upper[] = "0123456789ABCDEF";
        !           450: static char hexdig_lower[] = "0123456789abcdef";
        !           451: 
        !           452: /**
        !           453:  * Described in header.
        !           454:  */
        !           455: chunk_t chunk_to_hex(chunk_t chunk, char *buf, bool uppercase)
        !           456: {
        !           457:        int i, len;
        !           458:        char *hexdig = hexdig_lower;
        !           459: 
        !           460:        if (uppercase)
        !           461:        {
        !           462:                hexdig = hexdig_upper;
        !           463:        }
        !           464: 
        !           465:        len = chunk.len * 2;
        !           466:        if (!buf)
        !           467:        {
        !           468:                buf = malloc(len + 1);
        !           469:        }
        !           470:        buf[len] = '\0';
        !           471: 
        !           472:        for (i = 0; i < chunk.len; i++)
        !           473:        {
        !           474:                buf[i*2]   = hexdig[(chunk.ptr[i] >> 4) & 0xF];
        !           475:                buf[i*2+1] = hexdig[(chunk.ptr[i]     ) & 0xF];
        !           476:        }
        !           477:        return chunk_create(buf, len);
        !           478: }
        !           479: 
        !           480: /**
        !           481:  * convert a single hex character to its binary value
        !           482:  */
        !           483: static char hex2bin(char hex)
        !           484: {
        !           485:        switch (hex)
        !           486:        {
        !           487:                case '0' ... '9':
        !           488:                        return hex - '0';
        !           489:                case 'A' ... 'F':
        !           490:                        return hex - 'A' + 10;
        !           491:                case 'a' ... 'f':
        !           492:                        return hex - 'a' + 10;
        !           493:                default:
        !           494:                        return 0;
        !           495:        }
        !           496: }
        !           497: 
        !           498: /**
        !           499:  * Described in header.
        !           500:  */
        !           501: chunk_t chunk_from_hex(chunk_t hex, char *buf)
        !           502: {
        !           503:        int i, len;
        !           504:        u_char *ptr;
        !           505:        bool odd = FALSE;
        !           506: 
        !           507:        /* skip an optional 0x prefix */
        !           508:        if (hex.len > 1 && hex.ptr[1] == 'x' && hex.ptr[0] == '0')
        !           509:        {
        !           510:                hex = chunk_skip(hex, 2);
        !           511:        }
        !           512: 
        !           513:        /* subtract the number of optional ':' separation characters */
        !           514:        len = hex.len;
        !           515:        ptr = hex.ptr;
        !           516:        for (i = 0; i < hex.len; i++)
        !           517:        {
        !           518:                if (*ptr++ == ':')
        !           519:                {
        !           520:                        len--;
        !           521:                }
        !           522:        }
        !           523: 
        !           524:        /* compute the number of binary bytes */
        !           525:        if (len % 2)
        !           526:        {
        !           527:                odd = TRUE;
        !           528:                len++;
        !           529:        }
        !           530:        len /= 2;
        !           531: 
        !           532:        /* allocate buffer memory unless provided by caller */
        !           533:        if (!buf)
        !           534:        {
        !           535:                buf = malloc(len);
        !           536:        }
        !           537: 
        !           538:        /* buffer is filled from the right */
        !           539:        memset(buf, 0, len);
        !           540:        hex.ptr += hex.len;
        !           541: 
        !           542:        for (i = len - 1; i >= 0; i--)
        !           543:        {
        !           544:                /* skip separation characters */
        !           545:                if (*(--hex.ptr) == ':')
        !           546:                {
        !           547:                        --hex.ptr;
        !           548:                }
        !           549:                buf[i] = hex2bin(*hex.ptr);
        !           550:                if (i > 0 || !odd)
        !           551:                {
        !           552:                        buf[i] |= hex2bin(*(--hex.ptr)) << 4;
        !           553:                }
        !           554:        }
        !           555:        return chunk_create(buf, len);
        !           556: }
        !           557: 
        !           558: /** base 64 conversion digits */
        !           559: static char b64digits[] =
        !           560:        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        !           561: 
        !           562: /**
        !           563:  * Described in header.
        !           564:  */
        !           565: chunk_t chunk_to_base64(chunk_t chunk, char *buf)
        !           566: {
        !           567:        int i, len;
        !           568:        char *pos;
        !           569: 
        !           570:        len = chunk.len + ((3 - chunk.len % 3) % 3);
        !           571:        if (!buf)
        !           572:        {
        !           573:                buf = malloc(len * 4 / 3 + 1);
        !           574:        }
        !           575:        pos = buf;
        !           576:        for (i = 0; i < len; i+=3)
        !           577:        {
        !           578:                *pos++ = b64digits[chunk.ptr[i] >> 2];
        !           579:                if (i+1 >= chunk.len)
        !           580:                {
        !           581:                        *pos++ = b64digits[(chunk.ptr[i] & 0x03) << 4];
        !           582:                        *pos++ = '=';
        !           583:                        *pos++ = '=';
        !           584:                        break;
        !           585:                }
        !           586:                *pos++ = b64digits[((chunk.ptr[i] & 0x03) << 4) | (chunk.ptr[i+1] >> 4)];
        !           587:                if (i+2 >= chunk.len)
        !           588:                {
        !           589:                        *pos++ = b64digits[(chunk.ptr[i+1] & 0x0F) << 2];
        !           590:                        *pos++ = '=';
        !           591:                        break;
        !           592:                }
        !           593:                *pos++ = b64digits[((chunk.ptr[i+1] & 0x0F) << 2) | (chunk.ptr[i+2] >> 6)];
        !           594:                *pos++ = b64digits[chunk.ptr[i+2] & 0x3F];
        !           595:        }
        !           596:        *pos = '\0';
        !           597:        return chunk_create(buf, len * 4 / 3);
        !           598: }
        !           599: 
        !           600: /**
        !           601:  * convert a base 64 digit to its binary form (inversion of b64digits array)
        !           602:  */
        !           603: static int b642bin(char b64)
        !           604: {
        !           605:        switch (b64)
        !           606:        {
        !           607:                case 'A' ... 'Z':
        !           608:                        return b64 - 'A';
        !           609:                case 'a' ... 'z':
        !           610:                        return ('Z' - 'A' + 1) + b64 - 'a';
        !           611:                case '0' ... '9':
        !           612:                        return ('Z' - 'A' + 1) + ('z' - 'a' + 1) + b64 - '0';
        !           613:                case '+':
        !           614:                case '-':
        !           615:                        return 62;
        !           616:                case '/':
        !           617:                case '_':
        !           618:                        return 63;
        !           619:                case '=':
        !           620:                        return 0;
        !           621:                default:
        !           622:                        return -1;
        !           623:        }
        !           624: }
        !           625: 
        !           626: /**
        !           627:  * Described in header.
        !           628:  */
        !           629: chunk_t chunk_from_base64(chunk_t base64, char *buf)
        !           630: {
        !           631:        u_char *pos, byte[4];
        !           632:        int i, j, len, outlen;
        !           633: 
        !           634:        len = base64.len / 4 * 3;
        !           635:        if (!buf)
        !           636:        {
        !           637:                buf = malloc(len);
        !           638:        }
        !           639:        pos = base64.ptr;
        !           640:        outlen = 0;
        !           641:        for (i = 0; i < len; i+=3)
        !           642:        {
        !           643:                outlen += 3;
        !           644:                for (j = 0; j < 4; j++)
        !           645:                {
        !           646:                        if (*pos == '=' && outlen > 0)
        !           647:                        {
        !           648:                                outlen--;
        !           649:                        }
        !           650:                        byte[j] = b642bin(*pos++);
        !           651:                }
        !           652:                buf[i] = (byte[0] << 2) | (byte[1] >> 4);
        !           653:                buf[i+1] = (byte[1] << 4) | (byte[2] >> 2);
        !           654:                buf[i+2] = (byte[2] << 6) | (byte[3]);
        !           655:        }
        !           656:        return chunk_create(buf, outlen);
        !           657: }
        !           658: 
        !           659: /** base 32 conversion digits */
        !           660: static char b32digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
        !           661: 
        !           662: /**
        !           663:  * Described in header.
        !           664:  */
        !           665: chunk_t chunk_to_base32(chunk_t chunk, char *buf)
        !           666: {
        !           667:        int i, len;
        !           668:        char *pos;
        !           669: 
        !           670:        len = chunk.len + ((5 - chunk.len % 5) % 5);
        !           671:        if (!buf)
        !           672:        {
        !           673:                buf = malloc(len * 8 / 5 + 1);
        !           674:        }
        !           675:        pos = buf;
        !           676:        for (i = 0; i < len; i+=5)
        !           677:        {
        !           678:                *pos++ = b32digits[chunk.ptr[i] >> 3];
        !           679:                if (i+1 >= chunk.len)
        !           680:                {
        !           681:                        *pos++ = b32digits[(chunk.ptr[i] & 0x07) << 2];
        !           682:                        memset(pos, '=', 6);
        !           683:                        pos += 6;
        !           684:                        break;
        !           685:                }
        !           686:                *pos++ = b32digits[((chunk.ptr[i] & 0x07) << 2) |
        !           687:                                                   (chunk.ptr[i+1] >> 6)];
        !           688:                *pos++ = b32digits[(chunk.ptr[i+1] & 0x3E) >> 1];
        !           689:                if (i+2 >= chunk.len)
        !           690:                {
        !           691:                        *pos++ = b32digits[(chunk.ptr[i+1] & 0x01) << 4];
        !           692:                        memset(pos, '=', 4);
        !           693:                        pos += 4;
        !           694:                        break;
        !           695:                }
        !           696:                *pos++ = b32digits[((chunk.ptr[i+1] & 0x01) << 4) |
        !           697:                                                   (chunk.ptr[i+2] >> 4)];
        !           698:                if (i+3 >= chunk.len)
        !           699:                {
        !           700:                        *pos++ = b32digits[(chunk.ptr[i+2] & 0x0F) << 1];
        !           701:                        memset(pos, '=', 3);
        !           702:                        pos += 3;
        !           703:                        break;
        !           704:                }
        !           705:                *pos++ = b32digits[((chunk.ptr[i+2] & 0x0F) << 1) |
        !           706:                                                   (chunk.ptr[i+3] >> 7)];
        !           707:                *pos++ = b32digits[(chunk.ptr[i+3] & 0x7F) >> 2];
        !           708:                if (i+4 >= chunk.len)
        !           709:                {
        !           710:                        *pos++ = b32digits[(chunk.ptr[i+3] & 0x03) << 3];
        !           711:                        *pos++ = '=';
        !           712:                        break;
        !           713:                }
        !           714:                *pos++ = b32digits[((chunk.ptr[i+3] & 0x03) << 3) |
        !           715:                                                   (chunk.ptr[i+4] >> 5)];
        !           716:                *pos++ = b32digits[chunk.ptr[i+4] & 0x1F];
        !           717:        }
        !           718:        *pos = '\0';
        !           719:        return chunk_create(buf, len * 8 / 5);
        !           720: }
        !           721: 
        !           722: /**
        !           723:  * Described in header.
        !           724:  */
        !           725: int chunk_compare(chunk_t a, chunk_t b)
        !           726: {
        !           727:        int compare_len = a.len - b.len;
        !           728:        int len = (compare_len < 0)? a.len : b.len;
        !           729: 
        !           730:        if (compare_len != 0 || len == 0)
        !           731:        {
        !           732:                return compare_len;
        !           733:        }
        !           734:        return memcmp(a.ptr, b.ptr, len);
        !           735: };
        !           736: 
        !           737: 
        !           738: /**
        !           739:  * Described in header.
        !           740:  */
        !           741: bool chunk_increment(chunk_t chunk)
        !           742: {
        !           743:        int i;
        !           744: 
        !           745:        for (i = chunk.len - 1; i >= 0; i--)
        !           746:        {
        !           747:                if (++chunk.ptr[i] != 0)
        !           748:                {
        !           749:                        return FALSE;
        !           750:                }
        !           751:        }
        !           752:        return TRUE;
        !           753: }
        !           754: 
        !           755: /*
        !           756:  * Described in header
        !           757:  */
        !           758: chunk_t chunk_copy_pad(chunk_t dst, chunk_t src, u_char chr)
        !           759: {
        !           760:        if (dst.ptr)
        !           761:        {
        !           762:                if (dst.len > src.len)
        !           763:                {
        !           764:                        memcpy(dst.ptr + dst.len - src.len, src.ptr, src.len);
        !           765:                        memset(dst.ptr, chr, dst.len - src.len);
        !           766:                }
        !           767:                else
        !           768:                {
        !           769:                        memcpy(dst.ptr, src.ptr + src.len - dst.len, dst.len);
        !           770:                }
        !           771:        }
        !           772:        return dst;
        !           773: }
        !           774: 
        !           775: /**
        !           776:  * Remove non-printable characters from a chunk.
        !           777:  */
        !           778: bool chunk_printable(chunk_t chunk, chunk_t *sane, char replace)
        !           779: {
        !           780:        bool printable = TRUE;
        !           781:        int i;
        !           782: 
        !           783:        if (sane)
        !           784:        {
        !           785:                *sane = chunk_clone(chunk);
        !           786:        }
        !           787:        for (i = 0; i < chunk.len; i++)
        !           788:        {
        !           789:                if (!isprint(chunk.ptr[i]))
        !           790:                {
        !           791:                        if (sane)
        !           792:                        {
        !           793:                                sane->ptr[i] = replace;
        !           794:                        }
        !           795:                        printable = FALSE;
        !           796:                }
        !           797:        }
        !           798:        return printable;
        !           799: }
        !           800: 
        !           801: /**
        !           802:  * Helper functions for chunk_mac()
        !           803:  */
        !           804: static inline uint64_t sipget(u_char *in)
        !           805: {
        !           806:        uint64_t v = 0;
        !           807:        int i;
        !           808: 
        !           809:        for (i = 0; i < 64; i += 8, ++in)
        !           810:        {
        !           811:                v |= ((uint64_t)*in) << i;
        !           812:        }
        !           813:        return v;
        !           814: }
        !           815: 
        !           816: static inline uint64_t siprotate(uint64_t v, int shift)
        !           817: {
        !           818:         return (v << shift) | (v >> (64 - shift));
        !           819: }
        !           820: 
        !           821: static inline void sipround(uint64_t *v0, uint64_t *v1, uint64_t *v2,
        !           822:                                                        uint64_t *v3)
        !           823: {
        !           824:        *v0 += *v1;
        !           825:        *v1 = siprotate(*v1, 13);
        !           826:        *v1 ^= *v0;
        !           827:        *v0 = siprotate(*v0, 32);
        !           828: 
        !           829:        *v2 += *v3;
        !           830:        *v3 = siprotate(*v3, 16);
        !           831:        *v3 ^= *v2;
        !           832: 
        !           833:        *v2 += *v1;
        !           834:        *v1 = siprotate(*v1, 17);
        !           835:        *v1 ^= *v2;
        !           836:        *v2 = siprotate(*v2, 32);
        !           837: 
        !           838:        *v0 += *v3;
        !           839:        *v3 = siprotate(*v3, 21);
        !           840:        *v3 ^= *v0;
        !           841: }
        !           842: 
        !           843: static inline void sipcompress(uint64_t *v0, uint64_t *v1, uint64_t *v2,
        !           844:                                                           uint64_t *v3, uint64_t m)
        !           845: {
        !           846:        *v3 ^= m;
        !           847:        sipround(v0, v1, v2, v3);
        !           848:        sipround(v0, v1, v2, v3);
        !           849:        *v0 ^= m;
        !           850: }
        !           851: 
        !           852: static inline uint64_t siplast(size_t len, u_char *pos)
        !           853: {
        !           854:        uint64_t b;
        !           855:        int rem = len & 7;
        !           856: 
        !           857:        b = ((uint64_t)len) << 56;
        !           858:        switch (rem)
        !           859:        {
        !           860:                case 7:
        !           861:                        b |= ((uint64_t)pos[6]) << 48;
        !           862:                case 6:
        !           863:                        b |= ((uint64_t)pos[5]) << 40;
        !           864:                case 5:
        !           865:                        b |= ((uint64_t)pos[4]) << 32;
        !           866:                case 4:
        !           867:                        b |= ((uint64_t)pos[3]) << 24;
        !           868:                case 3:
        !           869:                        b |= ((uint64_t)pos[2]) << 16;
        !           870:                case 2:
        !           871:                        b |= ((uint64_t)pos[1]) <<  8;
        !           872:                case 1:
        !           873:                        b |= ((uint64_t)pos[0]);
        !           874:                        break;
        !           875:                case 0:
        !           876:                        break;
        !           877:        }
        !           878:        return b;
        !           879: }
        !           880: 
        !           881: /**
        !           882:  * Calculate SipHash-2-4 with an optional first block given as argument.
        !           883:  */
        !           884: static uint64_t chunk_mac_inc(chunk_t chunk, u_char *key, uint64_t m)
        !           885: {
        !           886:        uint64_t v0, v1, v2, v3, k0, k1;
        !           887:        size_t len = chunk.len;
        !           888:        u_char *pos = chunk.ptr, *end;
        !           889: 
        !           890:        end = chunk.ptr + len - (len % 8);
        !           891: 
        !           892:        k0 = sipget(key);
        !           893:        k1 = sipget(key + 8);
        !           894: 
        !           895:        v0 = k0 ^ 0x736f6d6570736575ULL;
        !           896:        v1 = k1 ^ 0x646f72616e646f6dULL;
        !           897:        v2 = k0 ^ 0x6c7967656e657261ULL;
        !           898:        v3 = k1 ^ 0x7465646279746573ULL;
        !           899: 
        !           900:        if (m)
        !           901:        {
        !           902:                sipcompress(&v0, &v1, &v2, &v3, m);
        !           903:        }
        !           904: 
        !           905:        /* compression with c = 2 */
        !           906:        for (; pos != end; pos += 8)
        !           907:        {
        !           908:                m = sipget(pos);
        !           909:                sipcompress(&v0, &v1, &v2, &v3, m);
        !           910:        }
        !           911:        sipcompress(&v0, &v1, &v2, &v3, siplast(len, pos));
        !           912: 
        !           913:        /* finalization with d = 4 */
        !           914:        v2 ^= 0xff;
        !           915:        sipround(&v0, &v1, &v2, &v3);
        !           916:        sipround(&v0, &v1, &v2, &v3);
        !           917:        sipround(&v0, &v1, &v2, &v3);
        !           918:        sipround(&v0, &v1, &v2, &v3);
        !           919:        return v0 ^ v1 ^ v2  ^ v3;
        !           920: }
        !           921: 
        !           922: /**
        !           923:  * Described in header.
        !           924:  */
        !           925: uint64_t chunk_mac(chunk_t chunk, u_char *key)
        !           926: {
        !           927:        return chunk_mac_inc(chunk, key, 0);
        !           928: }
        !           929: 
        !           930: /**
        !           931:  * Secret key allocated randomly with chunk_hash_seed().
        !           932:  */
        !           933: static u_char hash_key[16] = {};
        !           934: 
        !           935: /**
        !           936:  * Static key used in case predictable hash values are required.
        !           937:  */
        !           938: static u_char static_key[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
        !           939:                                                          0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
        !           940: 
        !           941: /**
        !           942:  * See header
        !           943:  */
        !           944: void chunk_hash_seed()
        !           945: {
        !           946:        static bool seeded = FALSE;
        !           947:        ssize_t len;
        !           948:        size_t done = 0;
        !           949:        int fd;
        !           950: 
        !           951:        if (seeded)
        !           952:        {
        !           953:                /* just once to have the same seed during the whole process lifetimes */
        !           954:                return;
        !           955:        }
        !           956: 
        !           957:        fd = open("/dev/urandom", O_RDONLY);
        !           958:        if (fd >= 0)
        !           959:        {
        !           960:                while (done < sizeof(hash_key))
        !           961:                {
        !           962:                        len = read(fd, hash_key + done, sizeof(hash_key) - done);
        !           963:                        if (len < 0)
        !           964:                        {
        !           965:                                break;
        !           966:                        }
        !           967:                        done += len;
        !           968:                }
        !           969:                close(fd);
        !           970:        }
        !           971:        /* on error we use random() to generate the key (better than nothing) */
        !           972:        if (done < sizeof(hash_key))
        !           973:        {
        !           974:                srandom(time(NULL) + getpid());
        !           975:                for (; done < sizeof(hash_key); done++)
        !           976:                {
        !           977:                        hash_key[done] = (u_char)random();
        !           978:                }
        !           979:        }
        !           980:        seeded = TRUE;
        !           981: }
        !           982: 
        !           983: /**
        !           984:  * Described in header.
        !           985:  */
        !           986: uint32_t chunk_hash_inc(chunk_t chunk, uint32_t hash)
        !           987: {
        !           988:        /* we could use a mac of the previous hash, but this is faster */
        !           989:        return chunk_mac_inc(chunk, hash_key, ((uint64_t)hash) << 32 | hash);
        !           990: }
        !           991: 
        !           992: /**
        !           993:  * Described in header.
        !           994:  */
        !           995: uint32_t chunk_hash(chunk_t chunk)
        !           996: {
        !           997:        return chunk_mac(chunk, hash_key);
        !           998: }
        !           999: 
        !          1000: /**
        !          1001:  * Described in header.
        !          1002:  */
        !          1003: uint32_t chunk_hash_static_inc(chunk_t chunk, uint32_t hash)
        !          1004: {      /* we could use a mac of the previous hash, but this is faster */
        !          1005:        return chunk_mac_inc(chunk, static_key, ((uint64_t)hash) << 32 | hash);
        !          1006: }
        !          1007: 
        !          1008: /**
        !          1009:  * Described in header.
        !          1010:  */
        !          1011: uint32_t chunk_hash_static(chunk_t chunk)
        !          1012: {
        !          1013:        return chunk_mac(chunk, static_key);
        !          1014: }
        !          1015: 
        !          1016: /**
        !          1017:  * Described in header.
        !          1018:  */
        !          1019: uint16_t chunk_internet_checksum_inc(chunk_t data, uint16_t checksum)
        !          1020: {
        !          1021:        uint32_t sum = ntohs((uint16_t)~checksum);
        !          1022: 
        !          1023:        while (data.len > 1)
        !          1024:        {
        !          1025:                sum += untoh16(data.ptr);
        !          1026:                data = chunk_skip(data, 2);
        !          1027:        }
        !          1028:        if (data.len)
        !          1029:        {
        !          1030:                sum += (uint16_t)*data.ptr << 8;
        !          1031:        }
        !          1032:        while (sum >> 16)
        !          1033:        {
        !          1034:                sum = (sum & 0xffff) + (sum >> 16);
        !          1035:        }
        !          1036:        return htons(~sum);
        !          1037: }
        !          1038: 
        !          1039: /**
        !          1040:  * Described in header.
        !          1041:  */
        !          1042: uint16_t chunk_internet_checksum(chunk_t data)
        !          1043: {
        !          1044:        return chunk_internet_checksum_inc(data, 0xffff);
        !          1045: }
        !          1046: 
        !          1047: /**
        !          1048:  * Described in header.
        !          1049:  */
        !          1050: int chunk_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
        !          1051:                                          const void *const *args)
        !          1052: {
        !          1053:        chunk_t *chunk = *((chunk_t**)(args[0]));
        !          1054:        bool first = TRUE;
        !          1055:        chunk_t copy = *chunk;
        !          1056:        int written = 0;
        !          1057: 
        !          1058:        if (!spec->hash && !spec->plus)
        !          1059:        {
        !          1060:                u_int chunk_len = chunk->len;
        !          1061:                const void *new_args[] = {&chunk->ptr, &chunk_len};
        !          1062:                return mem_printf_hook(data, spec, new_args);
        !          1063:        }
        !          1064: 
        !          1065:        while (copy.len > 0)
        !          1066:        {
        !          1067:                if (first)
        !          1068:                {
        !          1069:                        first = FALSE;
        !          1070:                }
        !          1071:                else if (!spec->plus)
        !          1072:                {
        !          1073:                        written += print_in_hook(data, ":");
        !          1074:                }
        !          1075:                written += print_in_hook(data, "%02x", *copy.ptr++);
        !          1076:                copy.len--;
        !          1077:        }
        !          1078:        return written;
        !          1079: }

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