00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <config.h>
00023
00024 #include <isc/base64.h>
00025 #include <isc/buffer.h>
00026 #include <isc/lex.h>
00027 #include <isc/string.h>
00028 #include <isc/util.h>
00029
00030 #define RETERR(x) do { \
00031 isc_result_t _r = (x); \
00032 if (_r != ISC_R_SUCCESS) \
00033 return (_r); \
00034 } while (0)
00035
00036
00037
00038
00039
00040
00041
00042 static isc_result_t
00043 str_totext(const char *source, isc_buffer_t *target);
00044
00045 static isc_result_t
00046 mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length);
00047
00048 static const char base64[] =
00049 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
00050
00051
00052 isc_result_t
00053 isc_base64_totext(isc_region_t *source, int wordlength,
00054 const char *wordbreak, isc_buffer_t *target)
00055 {
00056 char buf[5];
00057 unsigned int loops = 0;
00058
00059 if (wordlength < 4)
00060 wordlength = 4;
00061
00062 memset(buf, 0, sizeof(buf));
00063 while (source->length > 2) {
00064 buf[0] = base64[(source->base[0]>>2)&0x3f];
00065 buf[1] = base64[((source->base[0]<<4)&0x30)|
00066 ((source->base[1]>>4)&0x0f)];
00067 buf[2] = base64[((source->base[1]<<2)&0x3c)|
00068 ((source->base[2]>>6)&0x03)];
00069 buf[3] = base64[source->base[2]&0x3f];
00070 RETERR(str_totext(buf, target));
00071 isc_region_consume(source, 3);
00072
00073 loops++;
00074 if (source->length != 0 &&
00075 (int)((loops + 1) * 4) >= wordlength)
00076 {
00077 loops = 0;
00078 RETERR(str_totext(wordbreak, target));
00079 }
00080 }
00081 if (source->length == 2) {
00082 buf[0] = base64[(source->base[0]>>2)&0x3f];
00083 buf[1] = base64[((source->base[0]<<4)&0x30)|
00084 ((source->base[1]>>4)&0x0f)];
00085 buf[2] = base64[((source->base[1]<<2)&0x3c)];
00086 buf[3] = '=';
00087 RETERR(str_totext(buf, target));
00088 isc_region_consume(source, 2);
00089 } else if (source->length == 1) {
00090 buf[0] = base64[(source->base[0]>>2)&0x3f];
00091 buf[1] = base64[((source->base[0]<<4)&0x30)];
00092 buf[2] = buf[3] = '=';
00093 RETERR(str_totext(buf, target));
00094 isc_region_consume(source, 1);
00095 }
00096 return (ISC_R_SUCCESS);
00097 }
00098
00099
00100
00101
00102 typedef struct {
00103 int length;
00104 isc_buffer_t *target;
00105 int digits;
00106 isc_boolean_t seen_end;
00107 int val[4];
00108 } base64_decode_ctx_t;
00109
00110 static inline void
00111 base64_decode_init(base64_decode_ctx_t *ctx, int length, isc_buffer_t *target)
00112 {
00113 ctx->digits = 0;
00114 ctx->seen_end = ISC_FALSE;
00115 ctx->length = length;
00116 ctx->target = target;
00117 }
00118
00119 static inline isc_result_t
00120 base64_decode_char(base64_decode_ctx_t *ctx, int c) {
00121 char *s;
00122
00123 if (ctx->seen_end)
00124 return (ISC_R_BADBASE64);
00125 if ((s = strchr(base64, c)) == NULL)
00126 return (ISC_R_BADBASE64);
00127 ctx->val[ctx->digits++] = (int)(s - base64);
00128 if (ctx->digits == 4) {
00129 int n;
00130 unsigned char buf[3];
00131 if (ctx->val[0] == 64 || ctx->val[1] == 64)
00132 return (ISC_R_BADBASE64);
00133 if (ctx->val[2] == 64 && ctx->val[3] != 64)
00134 return (ISC_R_BADBASE64);
00135
00136
00137
00138 if (ctx->val[2] == 64 && (ctx->val[1] & 0xf) != 0)
00139 return (ISC_R_BADBASE64);
00140
00141
00142
00143
00144 if (ctx->val[3] == 64 && (ctx->val[2] & 0x3) != 0)
00145 return (ISC_R_BADBASE64);
00146 n = (ctx->val[2] == 64) ? 1 :
00147 (ctx->val[3] == 64) ? 2 : 3;
00148 if (n != 3) {
00149 ctx->seen_end = ISC_TRUE;
00150 if (ctx->val[2] == 64)
00151 ctx->val[2] = 0;
00152 if (ctx->val[3] == 64)
00153 ctx->val[3] = 0;
00154 }
00155 buf[0] = (ctx->val[0]<<2)|(ctx->val[1]>>4);
00156 buf[1] = (ctx->val[1]<<4)|(ctx->val[2]>>2);
00157 buf[2] = (ctx->val[2]<<6)|(ctx->val[3]);
00158 RETERR(mem_tobuffer(ctx->target, buf, n));
00159 if (ctx->length >= 0) {
00160 if (n > ctx->length)
00161 return (ISC_R_BADBASE64);
00162 else
00163 ctx->length -= n;
00164 }
00165 ctx->digits = 0;
00166 }
00167 return (ISC_R_SUCCESS);
00168 }
00169
00170 static inline isc_result_t
00171 base64_decode_finish(base64_decode_ctx_t *ctx) {
00172 if (ctx->length > 0)
00173 return (ISC_R_UNEXPECTEDEND);
00174 if (ctx->digits != 0)
00175 return (ISC_R_BADBASE64);
00176 return (ISC_R_SUCCESS);
00177 }
00178
00179 isc_result_t
00180 isc_base64_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
00181 base64_decode_ctx_t ctx;
00182 isc_textregion_t *tr;
00183 isc_token_t token;
00184 isc_boolean_t eol;
00185
00186 base64_decode_init(&ctx, length, target);
00187
00188 while (!ctx.seen_end && (ctx.length != 0)) {
00189 unsigned int i;
00190
00191 if (length > 0)
00192 eol = ISC_FALSE;
00193 else
00194 eol = ISC_TRUE;
00195 RETERR(isc_lex_getmastertoken(lexer, &token,
00196 isc_tokentype_string, eol));
00197 if (token.type != isc_tokentype_string)
00198 break;
00199 tr = &token.value.as_textregion;
00200 for (i = 0; i < tr->length; i++)
00201 RETERR(base64_decode_char(&ctx, tr->base[i]));
00202 }
00203 if (ctx.length < 0 && !ctx.seen_end)
00204 isc_lex_ungettoken(lexer, &token);
00205 RETERR(base64_decode_finish(&ctx));
00206 return (ISC_R_SUCCESS);
00207 }
00208
00209 isc_result_t
00210 isc_base64_decodestring(const char *cstr, isc_buffer_t *target) {
00211 base64_decode_ctx_t ctx;
00212
00213 base64_decode_init(&ctx, -1, target);
00214 for (;;) {
00215 int c = *cstr++;
00216 if (c == '\0')
00217 break;
00218 if (c == ' ' || c == '\t' || c == '\n' || c== '\r')
00219 continue;
00220 RETERR(base64_decode_char(&ctx, c));
00221 }
00222 RETERR(base64_decode_finish(&ctx));
00223 return (ISC_R_SUCCESS);
00224 }
00225
00226 static isc_result_t
00227 str_totext(const char *source, isc_buffer_t *target) {
00228 unsigned int l;
00229 isc_region_t region;
00230
00231 isc_buffer_availableregion(target, ®ion);
00232 l = strlen(source);
00233
00234 if (l > region.length)
00235 return (ISC_R_NOSPACE);
00236
00237 memmove(region.base, source, l);
00238 isc_buffer_add(target, l);
00239 return (ISC_R_SUCCESS);
00240 }
00241
00242 static isc_result_t
00243 mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) {
00244 isc_region_t tr;
00245
00246 isc_buffer_availableregion(target, &tr);
00247 if (length > tr.length)
00248 return (ISC_R_NOSPACE);
00249 memmove(tr.base, base, length);
00250 isc_buffer_add(target, length);
00251 return (ISC_R_SUCCESS);
00252 }