File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / lib / isc / base64.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 1 month ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    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.1.1.1 2012/05/29 12:08:38 misho 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>