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

1.1       misho       1: /*
                      2:  * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
                      3:  * Copyright (C) 1998-2001, 2003  Internet Software Consortium.
                      4:  *
                      5:  * Permission to use, copy, modify, and/or distribute this software for any
                      6:  * purpose with or without fee is hereby granted, provided that the above
                      7:  * copyright notice and this permission notice appear in all copies.
                      8:  *
                      9:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
                     10:  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
                     11:  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
                     12:  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
                     13:  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
                     14:  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
                     15:  * PERFORMANCE OF THIS SOFTWARE.
                     16:  */
                     17: 
                     18: /* $Id: base64.c,v 1.32 2007/06/19 23:47:17 tbox Exp $ */
                     19: 
                     20: /*! \file */
                     21: 
                     22: #include <config.h>
                     23: 
                     24: #include <isc/base64.h>
                     25: #include <isc/buffer.h>
                     26: #include <isc/lex.h>
                     27: #include <isc/string.h>
                     28: #include <isc/util.h>
                     29: 
                     30: #define RETERR(x) do { \
                     31:        isc_result_t _r = (x); \
                     32:        if (_r != ISC_R_SUCCESS) \
                     33:                return (_r); \
                     34:        } while (0)
                     35: 
                     36: 
                     37: /*@{*/
                     38: /*!
                     39:  * These static functions are also present in lib/dns/rdata.c.  I'm not
                     40:  * sure where they should go. -- bwelling
                     41:  */
                     42: static isc_result_t
                     43: str_totext(const char *source, isc_buffer_t *target);
                     44: 
                     45: static isc_result_t
                     46: mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length);
                     47: 
                     48: static const char base64[] =
                     49:        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
                     50: /*@}*/
                     51: 
                     52: isc_result_t
                     53: isc_base64_totext(isc_region_t *source, int wordlength,
                     54:                  const char *wordbreak, isc_buffer_t *target)
                     55: {
                     56:        char buf[5];
                     57:        unsigned int loops = 0;
                     58: 
                     59:        if (wordlength < 4)
                     60:                wordlength = 4;
                     61: 
                     62:        memset(buf, 0, sizeof(buf));
                     63:        while (source->length > 2) {
                     64:                buf[0] = base64[(source->base[0]>>2)&0x3f];
                     65:                buf[1] = base64[((source->base[0]<<4)&0x30)|
                     66:                                ((source->base[1]>>4)&0x0f)];
                     67:                buf[2] = base64[((source->base[1]<<2)&0x3c)|
                     68:                                ((source->base[2]>>6)&0x03)];
                     69:                buf[3] = base64[source->base[2]&0x3f];
                     70:                RETERR(str_totext(buf, target));
                     71:                isc_region_consume(source, 3);
                     72: 
                     73:                loops++;
                     74:                if (source->length != 0 &&
                     75:                    (int)((loops + 1) * 4) >= wordlength)
                     76:                {
                     77:                        loops = 0;
                     78:                        RETERR(str_totext(wordbreak, target));
                     79:                }
                     80:        }
                     81:        if (source->length == 2) {
                     82:                buf[0] = base64[(source->base[0]>>2)&0x3f];
                     83:                buf[1] = base64[((source->base[0]<<4)&0x30)|
                     84:                                ((source->base[1]>>4)&0x0f)];
                     85:                buf[2] = base64[((source->base[1]<<2)&0x3c)];
                     86:                buf[3] = '=';
                     87:                RETERR(str_totext(buf, target));
                     88:        } else if (source->length == 1) {
                     89:                buf[0] = base64[(source->base[0]>>2)&0x3f];
                     90:                buf[1] = base64[((source->base[0]<<4)&0x30)];
                     91:                buf[2] = buf[3] = '=';
                     92:                RETERR(str_totext(buf, target));
                     93:        }
                     94:        return (ISC_R_SUCCESS);
                     95: }
                     96: 
                     97: /*%
                     98:  * State of a base64 decoding process in progress.
                     99:  */
                    100: typedef struct {
                    101:        int length;             /*%< Desired length of binary data or -1 */
                    102:        isc_buffer_t *target;   /*%< Buffer for resulting binary data */
                    103:        int digits;             /*%< Number of buffered base64 digits */
                    104:        isc_boolean_t seen_end; /*%< True if "=" end marker seen */
                    105:        int val[4];
                    106: } base64_decode_ctx_t;
                    107: 
                    108: static inline void
                    109: base64_decode_init(base64_decode_ctx_t *ctx, int length, isc_buffer_t *target)
                    110: {
                    111:        ctx->digits = 0;
                    112:        ctx->seen_end = ISC_FALSE;
                    113:        ctx->length = length;
                    114:        ctx->target = target;
                    115: }
                    116: 
                    117: static inline isc_result_t
                    118: base64_decode_char(base64_decode_ctx_t *ctx, int c) {
                    119:        char *s;
                    120: 
                    121:        if (ctx->seen_end)
                    122:                return (ISC_R_BADBASE64);
                    123:        if ((s = strchr(base64, c)) == NULL)
                    124:                return (ISC_R_BADBASE64);
                    125:        ctx->val[ctx->digits++] = s - base64;
                    126:        if (ctx->digits == 4) {
                    127:                int n;
                    128:                unsigned char buf[3];
                    129:                if (ctx->val[0] == 64 || ctx->val[1] == 64)
                    130:                        return (ISC_R_BADBASE64);
                    131:                if (ctx->val[2] == 64 && ctx->val[3] != 64)
                    132:                        return (ISC_R_BADBASE64);
                    133:                /*
                    134:                 * Check that bits that should be zero are.
                    135:                 */
                    136:                if (ctx->val[2] == 64 && (ctx->val[1] & 0xf) != 0)
                    137:                        return (ISC_R_BADBASE64);
                    138:                /*
                    139:                 * We don't need to test for ctx->val[2] != 64 as
                    140:                 * the bottom two bits of 64 are zero.
                    141:                 */
                    142:                if (ctx->val[3] == 64 && (ctx->val[2] & 0x3) != 0)
                    143:                        return (ISC_R_BADBASE64);
                    144:                n = (ctx->val[2] == 64) ? 1 :
                    145:                        (ctx->val[3] == 64) ? 2 : 3;
                    146:                if (n != 3) {
                    147:                        ctx->seen_end = ISC_TRUE;
                    148:                        if (ctx->val[2] == 64)
                    149:                                ctx->val[2] = 0;
                    150:                        if (ctx->val[3] == 64)
                    151:                                ctx->val[3] = 0;
                    152:                }
                    153:                buf[0] = (ctx->val[0]<<2)|(ctx->val[1]>>4);
                    154:                buf[1] = (ctx->val[1]<<4)|(ctx->val[2]>>2);
                    155:                buf[2] = (ctx->val[2]<<6)|(ctx->val[3]);
                    156:                RETERR(mem_tobuffer(ctx->target, buf, n));
                    157:                if (ctx->length >= 0) {
                    158:                        if (n > ctx->length)
                    159:                                return (ISC_R_BADBASE64);
                    160:                        else
                    161:                                ctx->length -= n;
                    162:                }
                    163:                ctx->digits = 0;
                    164:        }
                    165:        return (ISC_R_SUCCESS);
                    166: }
                    167: 
                    168: static inline isc_result_t
                    169: base64_decode_finish(base64_decode_ctx_t *ctx) {
                    170:        if (ctx->length > 0)
                    171:                return (ISC_R_UNEXPECTEDEND);
                    172:        if (ctx->digits != 0)
                    173:                return (ISC_R_BADBASE64);
                    174:        return (ISC_R_SUCCESS);
                    175: }
                    176: 
                    177: isc_result_t
                    178: isc_base64_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
                    179:        base64_decode_ctx_t ctx;
                    180:        isc_textregion_t *tr;
                    181:        isc_token_t token;
                    182:        isc_boolean_t eol;
                    183: 
                    184:        base64_decode_init(&ctx, length, target);
                    185: 
                    186:        while (!ctx.seen_end && (ctx.length != 0)) {
                    187:                unsigned int i;
                    188: 
                    189:                if (length > 0)
                    190:                        eol = ISC_FALSE;
                    191:                else
                    192:                        eol = ISC_TRUE;
                    193:                RETERR(isc_lex_getmastertoken(lexer, &token,
                    194:                                              isc_tokentype_string, eol));
                    195:                if (token.type != isc_tokentype_string)
                    196:                        break;
                    197:                tr = &token.value.as_textregion;
                    198:                for (i = 0; i < tr->length; i++)
                    199:                        RETERR(base64_decode_char(&ctx, tr->base[i]));
                    200:        }
                    201:        if (ctx.length < 0 && !ctx.seen_end)
                    202:                isc_lex_ungettoken(lexer, &token);
                    203:        RETERR(base64_decode_finish(&ctx));
                    204:        return (ISC_R_SUCCESS);
                    205: }
                    206: 
                    207: isc_result_t
                    208: isc_base64_decodestring(const char *cstr, isc_buffer_t *target) {
                    209:        base64_decode_ctx_t ctx;
                    210: 
                    211:        base64_decode_init(&ctx, -1, target);
                    212:        for (;;) {
                    213:                int c = *cstr++;
                    214:                if (c == '\0')
                    215:                        break;
                    216:                if (c == ' ' || c == '\t' || c == '\n' || c== '\r')
                    217:                        continue;
                    218:                RETERR(base64_decode_char(&ctx, c));
                    219:        }
                    220:        RETERR(base64_decode_finish(&ctx));     
                    221:        return (ISC_R_SUCCESS);
                    222: }
                    223: 
                    224: static isc_result_t
                    225: str_totext(const char *source, isc_buffer_t *target) {
                    226:        unsigned int l;
                    227:        isc_region_t region;
                    228: 
                    229:        isc_buffer_availableregion(target, &region);
                    230:        l = strlen(source);
                    231: 
                    232:        if (l > region.length)
                    233:                return (ISC_R_NOSPACE);
                    234: 
                    235:        memcpy(region.base, source, l);
                    236:        isc_buffer_add(target, l);
                    237:        return (ISC_R_SUCCESS);
                    238: }
                    239: 
                    240: static isc_result_t
                    241: mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) {
                    242:        isc_region_t tr;
                    243: 
                    244:        isc_buffer_availableregion(target, &tr);
                    245:        if (length > tr.length)
                    246:                return (ISC_R_NOSPACE);
                    247:        memcpy(tr.base, base, length);
                    248:        isc_buffer_add(target, length);
                    249:        return (ISC_R_SUCCESS);
                    250: }

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