Annotation of embedaddon/strongswan/src/libstrongswan/utils/chunk.c, revision 1.1.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>