Commit | Line | Data |
---|---|---|
f4d091fb JH |
1 | /************************************************* |
2 | * Exim - an Internet mail transport agent * | |
3 | *************************************************/ | |
4 | ||
5 | /* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2004, 2015 */ | |
6 | /* License: GPL */ | |
7 | ||
8 | /* Copyright (c) University of Cambridge 1995 - 2015 */ | |
9 | /* See the file NOTICE for conditions of use and distribution. */ | |
10 | ||
11 | ||
12 | #include "exim.h" | |
13 | #ifdef WITH_CONTENT_SCAN /* file-IO specific decode function */ | |
14 | # include "mime.h" | |
15 | ||
16 | /* BASE64 decoder matrix */ | |
17 | static unsigned char mime_b64[256]={ | |
18 | /* 0 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, | |
19 | /* 16 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, | |
20 | /* 32 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 62, 128, 128, 128, 63, | |
21 | /* 48 */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 128, 128, 128, 255, 128, 128, | |
22 | /* 64 */ 128, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, | |
23 | /* 80 */ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 128, 128, 128, 128, 128, | |
24 | /* 96 */ 128, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, | |
25 | /* 112 */ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 128, 128, 128, 128, 128, | |
26 | /* 128 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, | |
27 | /* 144 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, | |
28 | /* 160 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, | |
29 | /* 176 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, | |
30 | /* 192 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, | |
31 | /* 208 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, | |
32 | /* 224 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, | |
33 | /* 240 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 | |
34 | }; | |
35 | ||
36 | /* decode base64 MIME part */ | |
37 | ssize_t | |
38 | mime_decode_base64(FILE * in, FILE * out, uschar * boundary) | |
39 | { | |
40 | uschar ibuf[MIME_MAX_LINE_LENGTH], obuf[MIME_MAX_LINE_LENGTH]; | |
41 | uschar *ipos, *opos; | |
42 | ssize_t len, size = 0; | |
43 | int bytestate = 0; | |
44 | ||
45 | opos = obuf; | |
46 | ||
47 | while (Ufgets(ibuf, MIME_MAX_LINE_LENGTH, in) != NULL) | |
48 | { | |
49 | if (boundary != NULL | |
50 | && Ustrncmp(ibuf, "--", 2) == 0 | |
51 | && Ustrncmp((ibuf+2), boundary, Ustrlen(boundary)) == 0 | |
52 | ) | |
53 | break; | |
54 | ||
55 | for (ipos = ibuf ; *ipos != '\r' && *ipos != '\n' && *ipos != 0; ++ipos) | |
56 | if (*ipos == '=') /* skip padding */ | |
57 | ++bytestate; | |
58 | ||
59 | else if (mime_b64[*ipos] == 128) /* skip bad characters */ | |
60 | mime_set_anomaly(MIME_ANOMALY_BROKEN_BASE64); | |
61 | ||
62 | /* simple state-machine */ | |
63 | else switch((bytestate++) & 3) | |
64 | { | |
65 | case 0: | |
66 | *opos = mime_b64[*ipos] << 2; break; | |
67 | case 1: | |
68 | *opos++ |= mime_b64[*ipos] >> 4; | |
69 | *opos = mime_b64[*ipos] << 4; break; | |
70 | case 2: | |
71 | *opos++ |= mime_b64[*ipos] >> 2; | |
72 | *opos = mime_b64[*ipos] << 6; break; | |
73 | case 3: | |
74 | *opos++ |= mime_b64[*ipos]; break; | |
75 | } | |
76 | ||
77 | /* something to write? */ | |
78 | len = opos - obuf; | |
79 | if (len > 0) | |
80 | { | |
81 | if (fwrite(obuf, 1, len, out) != len) return -1; /* error */ | |
82 | size += len; | |
83 | /* copy incomplete last byte to start of obuf, where we continue */ | |
84 | if ((bytestate & 3) != 0) | |
85 | *obuf = *opos; | |
86 | opos = obuf; | |
87 | } | |
88 | } /* while */ | |
89 | ||
90 | /* write out last byte if it was incomplete */ | |
91 | if (bytestate & 3) | |
92 | { | |
93 | if (fwrite(obuf, 1, 1, out) != 1) return -1; | |
94 | ++size; | |
95 | } | |
96 | ||
97 | return size; | |
98 | } | |
99 | ||
100 | #endif /*WITH_CONTENT_SCAN*/ | |
101 | ||
102 | /************************************************* | |
103 | /************************************************* | |
104 | /************************************************* | |
105 | /************************************************* | |
106 | /************************************************* | |
107 | /************************************************* | |
108 | /************************************************* | |
109 | /************************************************* | |
110 | /************************************************* | |
111 | /************************************************* | |
112 | /************************************************* | |
113 | /************************************************* | |
114 | /************************************************* | |
115 | /************************************************* | |
116 | /************************************************* | |
117 | /************************************************* | |
118 | ||
119 | ||
120 | /************************************************* | |
121 | * Decode byte-string in base 64 * | |
122 | *************************************************/ | |
123 | ||
124 | /* This function decodes a string in base 64 format as defined in RFC 2045 | |
125 | (MIME) and required by the SMTP AUTH extension (RFC 2554). The decoding | |
126 | algorithm is written out in a straightforward way. Turning it into some kind of | |
127 | compact loop is messy and would probably run more slowly. | |
128 | ||
129 | Arguments: | |
130 | code points to the coded string, zero-terminated | |
131 | ptr where to put the pointer to the result, which is in | |
132 | dynamic store, and zero-terminated | |
133 | ||
134 | Returns: the number of bytes in the result, | |
135 | or -1 if the input was malformed | |
136 | ||
137 | A zero is added on to the end to make it easy in cases where the result is to | |
138 | be interpreted as text. This is not included in the count. */ | |
139 | ||
140 | static uschar dec64table[] = { | |
141 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /* 0-15 */ | |
142 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /* 16-31 */ | |
143 | 255,255,255,255,255,255,255,255,255,255,255, 62,255,255,255, 63, /* 32-47 */ | |
144 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255,255,255,255, /* 48-63 */ | |
145 | 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 64-79 */ | |
146 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255, /* 80-95 */ | |
147 | 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 96-111 */ | |
148 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255 /* 112-127*/ | |
149 | }; | |
150 | ||
151 | int | |
152 | b64decode(uschar *code, uschar **ptr) | |
153 | { | |
154 | int x, y; | |
155 | uschar *result = store_get(3*(Ustrlen(code)/4) + 1); | |
156 | ||
157 | *ptr = result; | |
158 | ||
159 | /* Each cycle of the loop handles a quantum of 4 input bytes. For the last | |
160 | quantum this may decode to 1, 2, or 3 output bytes. */ | |
161 | ||
162 | while ((x = *code++) != 0) | |
163 | { | |
164 | if (x > 127 || (x = dec64table[x]) == 255) return -1; | |
165 | if ((y = *code++) == 0 || (y = dec64table[y]) == 255) | |
166 | return -1; | |
167 | ||
168 | *result++ = (x << 2) | (y >> 4); | |
169 | ||
170 | if ((x = *code++) == '=') | |
171 | { | |
172 | if (*code++ != '=' || *code != 0) return -1; | |
173 | } | |
174 | else | |
175 | { | |
176 | if (x > 127 || (x = dec64table[x]) == 255) return -1; | |
177 | *result++ = (y << 4) | (x >> 2); | |
178 | if ((y = (*code++)) == '=') | |
179 | { | |
180 | if (*code != 0) return -1; | |
181 | } | |
182 | else | |
183 | { | |
184 | if (y > 127 || (y = dec64table[y]) == 255) return -1; | |
185 | *result++ = (x << 6) | y; | |
186 | } | |
187 | } | |
188 | } | |
189 | ||
190 | *result = 0; | |
191 | return result - *ptr; | |
192 | } | |
193 | ||
194 | ||
195 | /************************************************* | |
196 | /************************************************* | |
197 | /************************************************* | |
198 | /************************************************* | |
199 | /************************************************* | |
200 | /************************************************* | |
201 | /************************************************* | |
202 | /************************************************* | |
203 | /************************************************* | |
204 | /************************************************* | |
205 | /************************************************* | |
206 | /************************************************* | |
207 | /************************************************* | |
208 | /************************************************* | |
209 | /************************************************* | |
210 | /************************************************* | |
211 | ||
212 | /************************************************* | |
213 | * Encode byte-string in base 64 * | |
214 | *************************************************/ | |
215 | ||
216 | /* This function encodes a string of bytes, containing any values whatsoever, | |
217 | in base 64 as defined in RFC 2045 (MIME) and required by the SMTP AUTH | |
218 | extension (RFC 2554). The encoding algorithm is written out in a | |
219 | straightforward way. Turning it into some kind of compact loop is messy and | |
220 | would probably run more slowly. | |
221 | ||
222 | Arguments: | |
223 | clear points to the clear text bytes | |
224 | len the number of bytes to encode | |
225 | ||
226 | Returns: a pointer to the zero-terminated base 64 string, which | |
227 | is in working store | |
228 | */ | |
229 | ||
230 | static uschar *enc64table = | |
231 | US"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | |
232 | ||
233 | uschar * | |
234 | b64encode(uschar *clear, int len) | |
235 | { | |
236 | uschar *code = store_get(4*((len+2)/3) + 1); | |
237 | uschar *p = code; | |
238 | ||
239 | while (len-- >0) | |
240 | { | |
241 | register int x, y; | |
242 | ||
243 | x = *clear++; | |
244 | *p++ = enc64table[(x >> 2) & 63]; | |
245 | ||
246 | if (len-- <= 0) | |
247 | { | |
248 | *p++ = enc64table[(x << 4) & 63]; | |
249 | *p++ = '='; | |
250 | *p++ = '='; | |
251 | break; | |
252 | } | |
253 | ||
254 | y = *clear++; | |
255 | *p++ = enc64table[((x << 4) | ((y >> 4) & 15)) & 63]; | |
256 | ||
257 | if (len-- <= 0) | |
258 | { | |
259 | *p++ = enc64table[(y << 2) & 63]; | |
260 | *p++ = '='; | |
261 | break; | |
262 | } | |
263 | ||
264 | x = *clear++; | |
265 | *p++ = enc64table[((y << 2) | ((x >> 6) & 3)) & 63]; | |
266 | ||
267 | *p++ = enc64table[x & 63]; | |
268 | } | |
269 | ||
270 | *p = 0; | |
271 | ||
272 | return code; | |
273 | } | |
274 | ||
275 | ||
276 | /* End of base64.c */ | |
277 | /* vi: sw ai sw=2 | |
278 | */ |