diff --git a/lib/isc/Makefile.in b/lib/isc/Makefile.in index 4e78a1859a..4ca451cd02 100644 --- a/lib/isc/Makefile.in +++ b/lib/isc/Makefile.in @@ -13,7 +13,7 @@ # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# $Id: Makefile.in,v 1.66 2000/09/20 19:06:02 gson Exp $ +# $Id: Makefile.in,v 1.67 2000/11/07 20:58:04 bwelling Exp $ srcdir = @srcdir@ VPATH = @srcdir@ @@ -51,7 +51,7 @@ WIN32OBJS = win32/condition.@O@ win32/dir.@O@ win32/file.@O@ \ OBJS = @ISC_EXTRA_OBJS@ \ assertions.@O@ base64.@O@ bitstring.@O@ buffer.@O@ \ bufferlist.@O@ commandline.@O@ error.@O@ event.@O@ \ - heap.@O@ hmacmd5.@O@ \ + heap.@O@ hex.@O@ hmacmd5.@O@ \ lex.@O@ lfsr.@O@ lib.@O@ log.@O@ \ md5.@O@ mem.@O@ mutexblock.@O@ netaddr.@O@ ondestroy.@O@ \ quota.@O@ random.@O@ \ @@ -64,7 +64,7 @@ OBJS = @ISC_EXTRA_OBJS@ \ SRCS = @ISC_EXTRA_SRCS@ \ assertions.c base64.c bitstring.c buffer.c \ bufferlist.c commandline.c error.c event.c \ - heap.c hmacmd5.c \ + heap.c hex.c hmacmd5.c \ lex.c lfsr.c lib.c log.c \ md5.c mem.c mutexblock.c netaddr.c ondestroy.c \ quota.c random.c \ diff --git a/lib/isc/hex.c b/lib/isc/hex.c new file mode 100644 index 0000000000..7a1f8a50de --- /dev/null +++ b/lib/isc/hex.c @@ -0,0 +1,224 @@ +#include + +#include +#include +#include +#include +#include + +#define RETERR(x) do { \ + isc_result_t _r = (x); \ + if (_r != ISC_R_SUCCESS) \ + return (_r); \ + } while (0) + + +/* + * BEW: These static functions are copied from lib/dns/rdata.c. + */ +static isc_result_t +str_totext(const char *source, isc_buffer_t *target); + +static isc_result_t +gettoken(isc_lex_t *lexer, isc_token_t *token, isc_tokentype_t expect, + isc_boolean_t eol); + +static isc_result_t +mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length); + +static const char hex[] = "0123456789ABCDEF"; + +isc_result_t +isc_hex_totext(isc_region_t *source, int wordlength, + const char *wordbreak, isc_buffer_t *target) +{ + char buf[3]; + unsigned int loops = 0; + + if (wordlength < 2) + wordlength = 2; + + memset(buf, 0, sizeof buf); + while (source->length > 0) { + buf[0] = hex[(source->base[0] >> 4) & 0xf]; + buf[1] = hex[(source->base[0]) & 0xf]; + RETERR(str_totext(buf, target)); + isc_region_consume(source, 1); + + loops++; + if (source->length != 0 && + (int)((loops + 1) * 2) >= wordlength) + { + loops = 0; + RETERR(str_totext(wordbreak, target)); + } + } + return (ISC_R_SUCCESS); +} + +/* + * State of a hex decoding process in progress. + */ +typedef struct { + int length; /* Desired length of binary data or -1 */ + isc_buffer_t *target; /* Buffer for resulting binary data */ + int digits; /* Number of buffered hex digits */ + int val[2]; +} hex_decode_ctx_t; + +static inline void +hex_decode_init(hex_decode_ctx_t *ctx, int length, isc_buffer_t *target) +{ + ctx->digits = 0; + ctx->length = length; + ctx->target = target; +} + +static inline isc_result_t +hex_decode_char(hex_decode_ctx_t *ctx, int c) { + char *s; + + if ((s = strchr(hex, c)) == NULL) + return (ISC_R_BADHEX); + ctx->val[ctx->digits++] = s - hex; + if (ctx->digits == 2) { + int n; + unsigned char num; + + num = (ctx->val[0] << 4) + (ctx->val[1]); + RETERR(mem_tobuffer(ctx->target, &num, 1)); + if (ctx->length >= 0) { + if (n > ctx->length) + return (ISC_R_BADHEX); + else + ctx->length -= n; + } + ctx->digits = 0; + } + return (ISC_R_SUCCESS); +} + +static inline isc_result_t +hex_decode_finish(hex_decode_ctx_t *ctx) { + if (ctx->length > 0) + return (ISC_R_UNEXPECTEDEND); + if (ctx->digits != 0) + return (ISC_R_BADHEX); + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) { + hex_decode_ctx_t ctx; + isc_textregion_t *tr; + isc_token_t token; + + hex_decode_init(&ctx, length, target); + + while (ctx.length != 0) { + unsigned int i; + + if (length > 0) + RETERR(gettoken(lexer, &token, isc_tokentype_string, + ISC_FALSE)); + else + RETERR(gettoken(lexer, &token, isc_tokentype_string, + ISC_TRUE)); + if (token.type != isc_tokentype_string) + break; + tr = &token.value.as_textregion; + for (i = 0 ;i < tr->length; i++) + RETERR(hex_decode_char(&ctx, tr->base[i])); + } + RETERR(hex_decode_finish(&ctx)); + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_hex_decodestring(isc_mem_t *mctx, char *cstr, isc_buffer_t *target) { + hex_decode_ctx_t ctx; + + UNUSED(mctx); + + hex_decode_init(&ctx, -1, target); + for (;;) { + int c = *cstr++; + if (c == '\0') + break; + if (c == ' ' || c == '\t' || c == '\n' || c== '\r') + continue; + RETERR(hex_decode_char(&ctx, c)); + } + RETERR(hex_decode_finish(&ctx)); + return (ISC_R_SUCCESS); +} + +static isc_result_t +str_totext(const char *source, isc_buffer_t *target) { + unsigned int l; + isc_region_t region; + + isc_buffer_availableregion(target, ®ion); + l = strlen(source); + + if (l > region.length) + return (ISC_R_NOSPACE); + + memcpy(region.base, source, l); + isc_buffer_add(target, l); + return (ISC_R_SUCCESS); +} + +static isc_result_t +mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) { + isc_region_t tr; + + isc_buffer_availableregion(target, &tr); + if (length > tr.length) + return (ISC_R_NOSPACE); + memcpy(tr.base, base, length); + isc_buffer_add(target, length); + return (ISC_R_SUCCESS); +} + +static isc_result_t +gettoken(isc_lex_t *lexer, isc_token_t *token, isc_tokentype_t expect, + isc_boolean_t eol) +{ + unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF | + ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE; + isc_result_t result; + + if (expect == isc_tokentype_qstring) + options |= ISC_LEXOPT_QSTRING; + else if (expect == isc_tokentype_number) + options |= ISC_LEXOPT_NUMBER; + result = isc_lex_gettoken(lexer, options, token); + switch (result) { + case ISC_R_SUCCESS: + break; + case ISC_R_NOMEMORY: + return (ISC_R_NOMEMORY); + case ISC_R_NOSPACE: + return (ISC_R_NOSPACE); + default: + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_lex_gettoken() failed: %s", + isc_result_totext(result)); + return (ISC_R_UNEXPECTED); + } + if (eol && ((token->type == isc_tokentype_eol) || + (token->type == isc_tokentype_eof))) + return (ISC_R_SUCCESS); + if (token->type == isc_tokentype_string && + expect == isc_tokentype_qstring) + return (ISC_R_SUCCESS); + if (token->type != expect) { + isc_lex_ungettoken(lexer, token); + if (token->type == isc_tokentype_eol || + token->type == isc_tokentype_eof) + return (ISC_R_UNEXPECTEDEND); + return (ISC_R_UNEXPECTEDTOKEN); + } + return (ISC_R_SUCCESS); +} diff --git a/lib/isc/include/isc/Makefile.in b/lib/isc/include/isc/Makefile.in index f20b44ccb3..8d1436b52c 100644 --- a/lib/isc/include/isc/Makefile.in +++ b/lib/isc/include/isc/Makefile.in @@ -13,7 +13,7 @@ # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# $Id: Makefile.in,v 1.44 2000/09/20 19:06:03 gson Exp $ +# $Id: Makefile.in,v 1.45 2000/11/07 20:58:06 bwelling Exp $ srcdir = @srcdir@ VPATH = @srcdir@ @@ -29,7 +29,7 @@ top_srcdir = @top_srcdir@ HEADERS = assertions.h base64.h bitstring.h boolean.h buffer.h \ bufferlist.h commandline.h entropy.h error.h event.h \ eventclass.h \ - file.h formatcheck.h fsaccess.h heap.h hmacmd5.h \ + file.h formatcheck.h fsaccess.h heap.h hex.h hmacmd5.h \ interfaceiter.h @ISC_IPV6_H@ lang.h lex.h \ lfsr.h lib.h list.h log.h magic.h md5.h mem.h msgcat.h \ mutexblock.h netaddr.h ondestroy.h os.h \ diff --git a/lib/isc/include/isc/hex.h b/lib/isc/include/isc/hex.h new file mode 100644 index 0000000000..bb29518681 --- /dev/null +++ b/lib/isc/include/isc/hex.h @@ -0,0 +1,78 @@ +#ifndef ISC_HEX_H +#define ISC_HEX_H 1 + +#include +#include + +ISC_LANG_BEGINDECLS + +/*** + *** Functions + ***/ + +isc_result_t +isc_hex_totext(isc_region_t *source, int wordlength, + const char *wordbreak, isc_buffer_t *target); +/* + * Convert data into hex encoded text. + * + * Notes: + * The hex encoded text in 'target' will be divided into + * words of at most 'wordlength' characters, separated by + * the 'wordbreak' string. No parentheses will surround + * the text. + * + * Requires: + * 'source' is a region containing binary data + * 'target' is a text buffer containing available space + * 'wordbreak' points to a null-terminated string of + * zero or more whitespace characters + * + * Ensures: + * target will contain the hex encoded version of the data + * in source. The 'used' pointer in target will be advanced as + * necessary. + */ + +isc_result_t +isc_hex_decodestring(isc_mem_t *mctx, char *cstr, isc_buffer_t *target); +/* + * Decode a null-terminated hex string. + * + * Requires: + * 'mctx' is non-null. + * 'cstr' is non-null. + * 'target' is a valid buffer. + * + * Returns: + * ISC_R_SUCCESS -- the entire decoded representation of 'cstring' + * fit in 'target'. + * ISC_R_BADHEX -- 'cstr' is not a valid hex encoding. + * + * Other error returns are any possible error code from: + * isc_lex_create(), + * isc_lex_openbuffer(), + * isc_hex_tobuffer(). + */ + +isc_result_t +isc_hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length); +/* + * Convert hex encoded text from a lexer context into data. + * + * Requires: + * 'lex' is a valid lexer context + * 'target' is a buffer containing binary data + * 'length' is an integer + * + * Ensures: + * target will contain the data represented by the hex encoded + * string parsed by the lexer. No more than length bytes will be read, + * if length is positive. The 'used' pointer in target will be + * advanced as necessary. + */ + + +ISC_LANG_ENDDECLS + +#endif /* ISC_HEX_H */ diff --git a/lib/isc/include/isc/result.h b/lib/isc/include/isc/result.h index 6bfa7a297e..e866211c22 100644 --- a/lib/isc/include/isc/result.h +++ b/lib/isc/include/isc/result.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: result.h,v 1.50 2000/08/15 23:30:22 tale Exp $ */ +/* $Id: result.h,v 1.51 2000/11/07 20:58:07 bwelling Exp $ */ #ifndef ISC_RESULT_H #define ISC_RESULT_H 1 @@ -72,11 +72,12 @@ #define ISC_R_QUEUEFULL 46 /* queue is full */ #define ISC_R_FAMILYMISMATCH 47 /* address family mismatch */ #define ISC_R_FAMILYNOSUPPORT 48 /* AF not supported */ +#define ISC_R_BADHEX 49 /* bad hex encoding */ /* * Not a result code: the number of results. */ -#define ISC_R_NRESULTS 49 +#define ISC_R_NRESULTS 50 ISC_LANG_BEGINDECLS diff --git a/lib/isc/result.c b/lib/isc/result.c index 826dbd3767..11af0a6341 100644 --- a/lib/isc/result.c +++ b/lib/isc/result.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: result.c,v 1.48 2000/08/15 01:43:36 marka Exp $ */ +/* $Id: result.c,v 1.49 2000/11/07 20:58:05 bwelling Exp $ */ #include @@ -86,7 +86,8 @@ static const char *text[ISC_R_NRESULTS] = { "not a directory", /* 45 */ "queue is full", /* 46 */ "address family mismatch", /* 47 */ - "address family not supported" /* 48 */ + "address family not supported", /* 48 */ + "bad hex encoding", /* 49 */ }; #define ISC_RESULT_RESULTSET 2