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, ®ion);
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>