added error message in case of incorrect padding
[strongswan.git] / src / libstrongswan / chunk.c
1 /**
2 * @file chunk.c
3 *
4 * @brief Pointer/lenght abstraction and its functions.
5 *
6 */
7
8 /*
9 * Copyright (C) 2005-2006 Martin Willi
10 * Copyright (C) 2005 Jan Hutter
11 * Hochschule fuer Technik Rapperswil
12 *
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * for more details.
22 */
23
24 #include <stdio.h>
25 #include <sys/stat.h>
26
27 #include "chunk.h"
28
29 #include <debug.h>
30 #include <printf_hook.h>
31 #include <utils/randomizer.h>
32
33 /**
34 * Empty chunk.
35 */
36 chunk_t chunk_empty = { NULL, 0 };
37
38 /**
39 * Described in header.
40 */
41 chunk_t chunk_create(u_char *ptr, size_t len)
42 {
43 chunk_t chunk = {ptr, len};
44 return chunk;
45 }
46
47 /**
48 * Described in header.
49 */
50 chunk_t chunk_create_clone(u_char *ptr, chunk_t chunk)
51 {
52 chunk_t clone = chunk_empty;
53
54 if (chunk.ptr && chunk.len > 0)
55 {
56 clone.ptr = ptr;
57 clone.len = chunk.len;
58 memcpy(clone.ptr, chunk.ptr, chunk.len);
59 }
60
61 return clone;
62 }
63
64 /**
65 * Decribed in header.
66 */
67 size_t chunk_length(const char* mode, ...)
68 {
69 va_list chunks;
70 size_t length = 0;
71
72 va_start(chunks, mode);
73 while (TRUE)
74 {
75 switch (*mode++)
76 {
77 case 'm':
78 case 'c':
79 {
80 chunk_t ch = va_arg(chunks, chunk_t);
81 length += ch.len;
82 continue;
83 }
84 default:
85 break;
86 }
87 break;
88 }
89 va_end(chunks);
90 return length;
91 }
92
93 /**
94 * Decribed in header.
95 */
96 chunk_t chunk_create_cat(u_char *ptr, const char* mode, ...)
97 {
98 va_list chunks;
99 chunk_t construct = chunk_create(ptr, 0);
100
101 va_start(chunks, mode);
102 while (TRUE)
103 {
104 bool free_chunk = FALSE;
105 switch (*mode++)
106 {
107 case 'm':
108 {
109 free_chunk = TRUE;
110 }
111 case 'c':
112 {
113 chunk_t ch = va_arg(chunks, chunk_t);
114 memcpy(ptr, ch.ptr, ch.len);
115 ptr += ch.len;
116 construct.len += ch.len;
117 if (free_chunk)
118 {
119 free(ch.ptr);
120 }
121 continue;
122 }
123 default:
124 break;
125 }
126 break;
127 }
128 va_end(chunks);
129
130 return construct;
131 }
132
133 /**
134 * Decribed in header.
135 */
136 void chunk_split(chunk_t chunk, const char *mode, ...)
137 {
138 va_list chunks;
139 size_t len;
140 chunk_t *ch;
141
142 va_start(chunks, mode);
143 while (TRUE)
144 {
145 if (*mode == '\0')
146 {
147 break;
148 }
149 len = va_arg(chunks, size_t);
150 ch = va_arg(chunks, chunk_t*);
151 /* a null chunk means skip len bytes */
152 if (ch == NULL)
153 {
154 chunk = chunk_skip(chunk, len);
155 continue;
156 }
157 switch (*mode++)
158 {
159 case 'm':
160 {
161 ch->len = min(chunk.len, len);
162 if (ch->len)
163 {
164 ch->ptr = chunk.ptr;
165 }
166 else
167 {
168 ch->ptr = NULL;
169 }
170 chunk = chunk_skip(chunk, ch->len);
171 continue;
172 }
173 case 'a':
174 {
175 ch->len = min(chunk.len, len);
176 if (ch->len)
177 {
178 ch->ptr = malloc(ch->len);
179 memcpy(ch->ptr, chunk.ptr, ch->len);
180 }
181 else
182 {
183 ch->ptr = NULL;
184 }
185 chunk = chunk_skip(chunk, ch->len);
186 continue;
187 }
188 case 'c':
189 {
190 ch->len = min(ch->len, chunk.len);
191 ch->len = min(ch->len, len);
192 if (ch->len)
193 {
194 memcpy(ch->ptr, chunk.ptr, ch->len);
195 }
196 else
197 {
198 ch->ptr = NULL;
199 }
200 chunk = chunk_skip(chunk, ch->len);
201 continue;
202 }
203 default:
204 break;
205 }
206 break;
207 }
208 va_end(chunks);
209 }
210
211 /**
212 * Described in header.
213 */
214 bool chunk_write(chunk_t chunk, const char *path, const char *label, mode_t mask, bool force)
215 {
216 mode_t oldmask;
217 FILE *fd;
218
219 if (!force)
220 {
221 fd = fopen(path, "r");
222 if (fd)
223 {
224 fclose(fd);
225 DBG1(" %s file '%s' already exists", label, path);
226 return FALSE;
227 }
228 }
229
230 /* set umask */
231 oldmask = umask(mask);
232
233 fd = fopen(path, "w");
234
235 if (fd)
236 {
237 fwrite(chunk.ptr, sizeof(u_char), chunk.len, fd);
238 fclose(fd);
239 DBG1(" written %s file '%s' (%u bytes)", label, path, chunk.len);
240 umask(oldmask);
241 return TRUE;
242 }
243 else
244 {
245 DBG1(" could not open %s file '%s' for writing", label, path);
246 umask(oldmask);
247 return FALSE;
248 }
249 }
250
251 /** hex conversion digits */
252 static char hexdig_upper[] = "0123456789ABCDEF";
253 static char hexdig_lower[] = "0123456789abcdef";
254
255 /**
256 * Described in header.
257 */
258 char *chunk_to_hex(chunk_t chunk, bool uppercase)
259 {
260 int i;
261 char *str;
262 char *hexdig = hexdig_lower;
263
264 if (uppercase)
265 {
266 hexdig = hexdig_upper;
267 }
268
269 str = malloc(chunk.len * 2 + 1);
270 str[chunk.len * 2] = '\0';
271
272 for (i = 0; i < chunk.len; i ++)
273 {
274 str[i*2] = hexdig[(chunk.ptr[i] >> 4) & 0xF];
275 str[i*2+1] = hexdig[(chunk.ptr[i] ) & 0xF];
276 }
277 return str;
278 }
279
280 /**
281 * Described in header.
282 */
283 void chunk_free(chunk_t *chunk)
284 {
285 free(chunk->ptr);
286 chunk->ptr = NULL;
287 chunk->len = 0;
288 }
289
290 /**
291 * Described in header.
292 */
293 void chunk_free_randomized(chunk_t *chunk)
294 {
295 if (chunk->ptr)
296 {
297 if (chunk->len > 0)
298 {
299 randomizer_t *randomizer = randomizer_create();
300
301 randomizer->get_pseudo_random_bytes(randomizer,
302 chunk->len, chunk->ptr);
303 randomizer->destroy(randomizer);
304 };
305 free(chunk->ptr);
306 chunk->ptr = NULL;
307 }
308 chunk->len = 0;
309 }
310
311 /**
312 * Described in header.
313 */
314 chunk_t chunk_skip(chunk_t chunk, size_t bytes)
315 {
316 if (chunk.len > bytes)
317 {
318 chunk.ptr += bytes;
319 chunk.len -= bytes;
320 return chunk;
321 }
322 return chunk_empty;
323 }
324
325 /**
326 * Described in header.
327 */
328 int chunk_compare(chunk_t a, chunk_t b)
329 {
330 int compare_len = a.len - b.len;
331 int len = (compare_len < 0)? a.len : b.len;
332
333 if (compare_len != 0 || len == 0)
334 {
335 return compare_len;
336 }
337 return memcmp(a.ptr, b.ptr, len);
338 };
339
340 /**
341 * Described in header.
342 */
343 bool chunk_equals(chunk_t a, chunk_t b)
344 {
345 return a.ptr != NULL && b.ptr != NULL &&
346 a.len == b.len && memeq(a.ptr, b.ptr, a.len);
347 }
348
349 /**
350 * Described in header.
351 */
352 bool chunk_equals_or_null(chunk_t a, chunk_t b)
353 {
354 if (a.ptr == NULL || b.ptr == NULL)
355 return TRUE;
356 return a.len == b.len && memeq(a.ptr, b.ptr, a.len);
357 }
358
359 /**
360 * Number of bytes per line to dump raw data
361 */
362 #define BYTES_PER_LINE 16
363
364 /**
365 * output handler in printf() for byte ranges
366 */
367 static int print_bytes(FILE *stream, const struct printf_info *info,
368 const void *const *args)
369 {
370 char *bytes = *((void**)(args[0]));
371 int len = *((size_t*)(args[1]));
372
373 char buffer[BYTES_PER_LINE * 3];
374 char ascii_buffer[BYTES_PER_LINE + 1];
375 char *buffer_pos = buffer;
376 char *bytes_pos = bytes;
377 char *bytes_roof = bytes + len;
378 int line_start = 0;
379 int i = 0;
380 int written = 0;
381
382 written += fprintf(stream, "=> %d bytes @ %p", len, bytes);
383
384 while (bytes_pos < bytes_roof)
385 {
386 *buffer_pos++ = hexdig_upper[(*bytes_pos >> 4) & 0xF];
387 *buffer_pos++ = hexdig_upper[ *bytes_pos & 0xF];
388
389 ascii_buffer[i++] =
390 (*bytes_pos > 31 && *bytes_pos < 127) ? *bytes_pos : '.';
391
392 if (++bytes_pos == bytes_roof || i == BYTES_PER_LINE)
393 {
394 int padding = 3 * (BYTES_PER_LINE - i);
395 int written;
396
397 while (padding--)
398 {
399 *buffer_pos++ = ' ';
400 }
401 *buffer_pos++ = '\0';
402 ascii_buffer[i] = '\0';
403
404 written += fprintf(stream, "\n%4d: %s %s",
405 line_start, buffer, ascii_buffer);
406
407
408 buffer_pos = buffer;
409 line_start += BYTES_PER_LINE;
410 i = 0;
411 }
412 else
413 {
414 *buffer_pos++ = ' ';
415 }
416 }
417 return written;
418 }
419
420 /**
421 * output handler in printf() for chunks
422 */
423 static int print_chunk(FILE *stream, const struct printf_info *info,
424 const void *const *args)
425 {
426 chunk_t *chunk = *((chunk_t**)(args[0]));
427 bool first = TRUE;
428 chunk_t copy = *chunk;
429 int written = 0;
430
431 if (!info->alt)
432 {
433 const void *new_args[] = {&chunk->ptr, &chunk->len};
434 return print_bytes(stream, info, new_args);
435 }
436
437 while (copy.len > 0)
438 {
439 if (first)
440 {
441 first = FALSE;
442 }
443 else
444 {
445 written += fprintf(stream, ":");
446 }
447 written += fprintf(stream, "%02x", *copy.ptr++);
448 copy.len--;
449 }
450 return written;
451 }
452
453 /**
454 * register printf() handlers
455 */
456 static void __attribute__ ((constructor))print_register()
457 {
458 register_printf_function(PRINTF_CHUNK, print_chunk, arginfo_ptr);
459 register_printf_function(PRINTF_BYTES, print_bytes, arginfo_ptr_int);
460 }