chunk: Provide a fallback chunk_map() if mmap is not available
[strongswan.git] / src / libstrongswan / utils / chunk.c
1 /*
2 * Copyright (C) 2008-2013 Tobias Brunner
3 * Copyright (C) 2005-2006 Martin Willi
4 * Copyright (C) 2005 Jan Hutter
5 * Hochschule fuer Technik Rapperswil
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #include <stdio.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #ifdef HAVE_MMAP
22 # include <sys/mman.h>
23 #endif
24 #include <fcntl.h>
25 #include <unistd.h>
26 #include <errno.h>
27 #include <pthread.h>
28 #include <ctype.h>
29
30 #include "chunk.h"
31 #include "debug.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_clone(u_char *ptr, chunk_t chunk)
42 {
43 chunk_t clone = chunk_empty;
44
45 if (chunk.ptr && chunk.len > 0)
46 {
47 clone.ptr = ptr;
48 clone.len = chunk.len;
49 memcpy(clone.ptr, chunk.ptr, chunk.len);
50 }
51
52 return clone;
53 }
54
55 /**
56 * Described in header.
57 */
58 size_t chunk_length(const char* mode, ...)
59 {
60 va_list chunks;
61 size_t length = 0;
62
63 va_start(chunks, mode);
64 while (TRUE)
65 {
66 switch (*mode++)
67 {
68 case 'm':
69 case 'c':
70 case 's':
71 {
72 chunk_t ch = va_arg(chunks, chunk_t);
73 length += ch.len;
74 continue;
75 }
76 default:
77 break;
78 }
79 break;
80 }
81 va_end(chunks);
82 return length;
83 }
84
85 /**
86 * Described in header.
87 */
88 chunk_t chunk_create_cat(u_char *ptr, const char* mode, ...)
89 {
90 va_list chunks;
91 chunk_t construct = chunk_create(ptr, 0);
92
93 va_start(chunks, mode);
94 while (TRUE)
95 {
96 bool free_chunk = FALSE, clear_chunk = FALSE;
97 chunk_t ch;
98
99 switch (*mode++)
100 {
101 case 's':
102 clear_chunk = TRUE;
103 /* FALL */
104 case 'm':
105 free_chunk = TRUE;
106 /* FALL */
107 case 'c':
108 ch = va_arg(chunks, chunk_t);
109 memcpy(ptr, ch.ptr, ch.len);
110 ptr += ch.len;
111 construct.len += ch.len;
112 if (clear_chunk)
113 {
114 chunk_clear(&ch);
115 }
116 else if (free_chunk)
117 {
118 free(ch.ptr);
119 }
120 continue;
121 default:
122 break;
123 }
124 break;
125 }
126 va_end(chunks);
127
128 return construct;
129 }
130
131 /**
132 * Described in header.
133 */
134 void chunk_split(chunk_t chunk, const char *mode, ...)
135 {
136 va_list chunks;
137 u_int len;
138 chunk_t *ch;
139
140 va_start(chunks, mode);
141 while (TRUE)
142 {
143 if (*mode == '\0')
144 {
145 break;
146 }
147 len = va_arg(chunks, u_int);
148 ch = va_arg(chunks, chunk_t*);
149 /* a null chunk means skip len bytes */
150 if (ch == NULL)
151 {
152 chunk = chunk_skip(chunk, len);
153 continue;
154 }
155 switch (*mode++)
156 {
157 case 'm':
158 {
159 ch->len = min(chunk.len, len);
160 if (ch->len)
161 {
162 ch->ptr = chunk.ptr;
163 }
164 else
165 {
166 ch->ptr = NULL;
167 }
168 chunk = chunk_skip(chunk, ch->len);
169 continue;
170 }
171 case 'a':
172 {
173 ch->len = min(chunk.len, len);
174 if (ch->len)
175 {
176 ch->ptr = malloc(ch->len);
177 memcpy(ch->ptr, chunk.ptr, ch->len);
178 }
179 else
180 {
181 ch->ptr = NULL;
182 }
183 chunk = chunk_skip(chunk, ch->len);
184 continue;
185 }
186 case 'c':
187 {
188 ch->len = min(ch->len, chunk.len);
189 ch->len = min(ch->len, len);
190 if (ch->len)
191 {
192 memcpy(ch->ptr, chunk.ptr, ch->len);
193 }
194 else
195 {
196 ch->ptr = NULL;
197 }
198 chunk = chunk_skip(chunk, ch->len);
199 continue;
200 }
201 default:
202 break;
203 }
204 break;
205 }
206 va_end(chunks);
207 }
208
209 /**
210 * Described in header.
211 */
212 bool chunk_write(chunk_t chunk, char *path, char *label, mode_t mask, bool force)
213 {
214 mode_t oldmask;
215 FILE *fd;
216 bool good = FALSE;
217
218 if (!force && access(path, F_OK) == 0)
219 {
220 DBG1(DBG_LIB, " %s file '%s' already exists", label, path);
221 return FALSE;
222 }
223 oldmask = umask(mask);
224 fd = fopen(path, "w");
225 if (fd)
226 {
227 if (fwrite(chunk.ptr, sizeof(u_char), chunk.len, fd) == chunk.len)
228 {
229 DBG1(DBG_LIB, " written %s file '%s' (%d bytes)",
230 label, path, chunk.len);
231 good = TRUE;
232 }
233 else
234 {
235 DBG1(DBG_LIB, " writing %s file '%s' failed: %s",
236 label, path, strerror(errno));
237 }
238 fclose(fd);
239 }
240 else
241 {
242 DBG1(DBG_LIB, " could not open %s file '%s': %s", label, path,
243 strerror(errno));
244 }
245 umask(oldmask);
246 return good;
247 }
248
249 /**
250 * Described in header.
251 */
252 bool chunk_from_fd(int fd, chunk_t *out)
253 {
254 struct stat sb;
255 char *buf, *tmp;
256 ssize_t len, total = 0, bufsize;
257
258 if (fstat(fd, &sb) == 0 && S_ISREG(sb.st_mode))
259 {
260 bufsize = sb.st_size;
261 }
262 else
263 {
264 bufsize = 256;
265 }
266 buf = malloc(bufsize);
267 if (!buf)
268 { /* for huge files */
269 return FALSE;
270 }
271
272 while (TRUE)
273 {
274 len = read(fd, buf + total, bufsize - total);
275 if (len < 0)
276 {
277 free(buf);
278 return FALSE;
279 }
280 if (len == 0)
281 {
282 break;
283 }
284 total += len;
285 if (total == bufsize)
286 {
287 bufsize *= 2;
288 tmp = realloc(buf, bufsize);
289 if (!tmp)
290 {
291 free(buf);
292 return FALSE;
293 }
294 buf = tmp;
295 }
296 }
297 if (total == 0)
298 {
299 free(buf);
300 buf = NULL;
301 }
302 else if (total < bufsize)
303 {
304 buf = realloc(buf, total);
305 }
306 *out = chunk_create(buf, total);
307 return TRUE;
308 }
309
310 /**
311 * Implementation for mmap()ed chunks
312 */
313 typedef struct {
314 /* public chunk interface */
315 chunk_t public;
316 /* FD of open file */
317 int fd;
318 /* mmap() address */
319 void *map;
320 /* size of map */
321 size_t len;
322 /* do we write? */
323 bool wr;
324 } mmaped_chunk_t;
325
326 /**
327 * See header.
328 */
329 chunk_t *chunk_map(char *path, bool wr)
330 {
331 mmaped_chunk_t *chunk;
332 struct stat sb;
333 int tmp;
334
335 INIT(chunk,
336 .fd = open(path, wr ? O_RDWR : O_RDONLY),
337 .wr = wr,
338 );
339
340 if (chunk->fd == -1)
341 {
342 free(chunk);
343 return NULL;
344 }
345 if (fstat(chunk->fd, &sb) == -1)
346 {
347 tmp = errno;
348 chunk_unmap(&chunk->public);
349 errno = tmp;
350 return NULL;
351 }
352 #ifdef HAVE_MMAP
353 chunk->len = sb.st_size;
354 /* map non-empty files only, as mmap() complains otherwise */
355 if (chunk->len)
356 {
357 /* in read-only mode, we allow writes, but don't sync to disk */
358 chunk->map = mmap(NULL, chunk->len, PROT_READ | PROT_WRITE,
359 wr ? MAP_SHARED : MAP_PRIVATE, chunk->fd, 0);
360 if (chunk->map == MAP_FAILED)
361 {
362 tmp = errno;
363 chunk_unmap(&chunk->public);
364 errno = tmp;
365 return NULL;
366 }
367 }
368 chunk->public = chunk_create(chunk->map, chunk->len);
369 #else /* !HAVE_MMAP */
370 if (!chunk_from_fd(chunk->fd, &chunk->public))
371 {
372 tmp = errno;
373 chunk_unmap(&chunk->public);
374 errno = tmp;
375 return NULL;
376 }
377 chunk->map = chunk->public.ptr;
378 chunk->len = chunk->public.len;
379 #endif /* !HAVE_MMAP */
380 return &chunk->public;
381 }
382
383 /**
384 * See header.
385 */
386 bool chunk_unmap(chunk_t *public)
387 {
388 mmaped_chunk_t *chunk;
389 bool ret = FALSE;
390 int tmp = 0;
391
392 chunk = (mmaped_chunk_t*)public;
393 #ifdef HAVE_MMAP
394 if (chunk->map && chunk->map != MAP_FAILED)
395 {
396 ret = munmap(chunk->map, chunk->len) == 0;
397 tmp = errno;
398 }
399 #else /* !HAVE_MMAP */
400 if (chunk->wr)
401 {
402 if (lseek(chunk->fd, 0, SEEK_SET) != -1)
403 {
404 int len, total = 0;
405
406 ret = TRUE;
407 while (total < chunk->len)
408 {
409 len = write(chunk->fd, chunk->map + total, chunk->len - total);
410 if (len <= 0)
411 {
412 ret = FALSE;
413 break;
414 }
415 total += len;
416 }
417 }
418 tmp = errno;
419 }
420 else
421 {
422 ret = TRUE;
423 }
424 free(chunk->map);
425 #endif /* !HAVE_MMAP */
426 close(chunk->fd);
427 free(chunk);
428 errno = tmp;
429
430 return ret;
431 }
432
433 /** hex conversion digits */
434 static char hexdig_upper[] = "0123456789ABCDEF";
435 static char hexdig_lower[] = "0123456789abcdef";
436
437 /**
438 * Described in header.
439 */
440 chunk_t chunk_to_hex(chunk_t chunk, char *buf, bool uppercase)
441 {
442 int i, len;
443 char *hexdig = hexdig_lower;
444
445 if (uppercase)
446 {
447 hexdig = hexdig_upper;
448 }
449
450 len = chunk.len * 2;
451 if (!buf)
452 {
453 buf = malloc(len + 1);
454 }
455 buf[len] = '\0';
456
457 for (i = 0; i < chunk.len; i++)
458 {
459 buf[i*2] = hexdig[(chunk.ptr[i] >> 4) & 0xF];
460 buf[i*2+1] = hexdig[(chunk.ptr[i] ) & 0xF];
461 }
462 return chunk_create(buf, len);
463 }
464
465 /**
466 * convert a signle hex character to its binary value
467 */
468 static char hex2bin(char hex)
469 {
470 switch (hex)
471 {
472 case '0' ... '9':
473 return hex - '0';
474 case 'A' ... 'F':
475 return hex - 'A' + 10;
476 case 'a' ... 'f':
477 return hex - 'a' + 10;
478 default:
479 return 0;
480 }
481 }
482
483 /**
484 * Described in header.
485 */
486 chunk_t chunk_from_hex(chunk_t hex, char *buf)
487 {
488 int i, len;
489 u_char *ptr;
490 bool odd = FALSE;
491
492 /* subtract the number of optional ':' separation characters */
493 len = hex.len;
494 ptr = hex.ptr;
495 for (i = 0; i < hex.len; i++)
496 {
497 if (*ptr++ == ':')
498 {
499 len--;
500 }
501 }
502
503 /* compute the number of binary bytes */
504 if (len % 2)
505 {
506 odd = TRUE;
507 len++;
508 }
509 len /= 2;
510
511 /* allocate buffer memory unless provided by caller */
512 if (!buf)
513 {
514 buf = malloc(len);
515 }
516
517 /* buffer is filled from the right */
518 memset(buf, 0, len);
519 hex.ptr += hex.len;
520
521 for (i = len - 1; i >= 0; i--)
522 {
523 /* skip separation characters */
524 if (*(--hex.ptr) == ':')
525 {
526 --hex.ptr;
527 }
528 buf[i] = hex2bin(*hex.ptr);
529 if (i > 0 || !odd)
530 {
531 buf[i] |= hex2bin(*(--hex.ptr)) << 4;
532 }
533 }
534 return chunk_create(buf, len);
535 }
536
537 /** base 64 conversion digits */
538 static char b64digits[] =
539 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
540
541 /**
542 * Described in header.
543 */
544 chunk_t chunk_to_base64(chunk_t chunk, char *buf)
545 {
546 int i, len;
547 char *pos;
548
549 len = chunk.len + ((3 - chunk.len % 3) % 3);
550 if (!buf)
551 {
552 buf = malloc(len * 4 / 3 + 1);
553 }
554 pos = buf;
555 for (i = 0; i < len; i+=3)
556 {
557 *pos++ = b64digits[chunk.ptr[i] >> 2];
558 if (i+1 >= chunk.len)
559 {
560 *pos++ = b64digits[(chunk.ptr[i] & 0x03) << 4];
561 *pos++ = '=';
562 *pos++ = '=';
563 break;
564 }
565 *pos++ = b64digits[((chunk.ptr[i] & 0x03) << 4) | (chunk.ptr[i+1] >> 4)];
566 if (i+2 >= chunk.len)
567 {
568 *pos++ = b64digits[(chunk.ptr[i+1] & 0x0F) << 2];
569 *pos++ = '=';
570 break;
571 }
572 *pos++ = b64digits[((chunk.ptr[i+1] & 0x0F) << 2) | (chunk.ptr[i+2] >> 6)];
573 *pos++ = b64digits[chunk.ptr[i+2] & 0x3F];
574 }
575 *pos = '\0';
576 return chunk_create(buf, len * 4 / 3);
577 }
578
579 /**
580 * convert a base 64 digit to its binary form (inversion of b64digits array)
581 */
582 static int b642bin(char b64)
583 {
584 switch (b64)
585 {
586 case 'A' ... 'Z':
587 return b64 - 'A';
588 case 'a' ... 'z':
589 return ('Z' - 'A' + 1) + b64 - 'a';
590 case '0' ... '9':
591 return ('Z' - 'A' + 1) + ('z' - 'a' + 1) + b64 - '0';
592 case '+':
593 case '-':
594 return 62;
595 case '/':
596 case '_':
597 return 63;
598 case '=':
599 return 0;
600 default:
601 return -1;
602 }
603 }
604
605 /**
606 * Described in header.
607 */
608 chunk_t chunk_from_base64(chunk_t base64, char *buf)
609 {
610 u_char *pos, byte[4];
611 int i, j, len, outlen;
612
613 len = base64.len / 4 * 3;
614 if (!buf)
615 {
616 buf = malloc(len);
617 }
618 pos = base64.ptr;
619 outlen = 0;
620 for (i = 0; i < len; i+=3)
621 {
622 outlen += 3;
623 for (j = 0; j < 4; j++)
624 {
625 if (*pos == '=')
626 {
627 outlen--;
628 }
629 byte[j] = b642bin(*pos++);
630 }
631 buf[i] = (byte[0] << 2) | (byte[1] >> 4);
632 buf[i+1] = (byte[1] << 4) | (byte[2] >> 2);
633 buf[i+2] = (byte[2] << 6) | (byte[3]);
634 }
635 return chunk_create(buf, outlen);
636 }
637
638 /** base 32 conversion digits */
639 static char b32digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
640
641 /**
642 * Described in header.
643 */
644 chunk_t chunk_to_base32(chunk_t chunk, char *buf)
645 {
646 int i, len;
647 char *pos;
648
649 len = chunk.len + ((5 - chunk.len % 5) % 5);
650 if (!buf)
651 {
652 buf = malloc(len * 8 / 5 + 1);
653 }
654 pos = buf;
655 for (i = 0; i < len; i+=5)
656 {
657 *pos++ = b32digits[chunk.ptr[i] >> 3];
658 if (i+1 >= chunk.len)
659 {
660 *pos++ = b32digits[(chunk.ptr[i] & 0x07) << 2];
661 memset(pos, '=', 6);
662 pos += 6;
663 break;
664 }
665 *pos++ = b32digits[((chunk.ptr[i] & 0x07) << 2) |
666 (chunk.ptr[i+1] >> 6)];
667 *pos++ = b32digits[(chunk.ptr[i+1] & 0x3E) >> 1];
668 if (i+2 >= chunk.len)
669 {
670 *pos++ = b32digits[(chunk.ptr[i+1] & 0x01) << 4];
671 memset(pos, '=', 4);
672 pos += 4;
673 break;
674 }
675 *pos++ = b32digits[((chunk.ptr[i+1] & 0x01) << 4) |
676 (chunk.ptr[i+2] >> 4)];
677 if (i+3 >= chunk.len)
678 {
679 *pos++ = b32digits[(chunk.ptr[i+2] & 0x0F) << 1];
680 memset(pos, '=', 3);
681 pos += 3;
682 break;
683 }
684 *pos++ = b32digits[((chunk.ptr[i+2] & 0x0F) << 1) |
685 (chunk.ptr[i+3] >> 7)];
686 *pos++ = b32digits[(chunk.ptr[i+3] & 0x7F) >> 2];
687 if (i+4 >= chunk.len)
688 {
689 *pos++ = b32digits[(chunk.ptr[i+3] & 0x03) << 3];
690 *pos++ = '=';
691 break;
692 }
693 *pos++ = b32digits[((chunk.ptr[i+3] & 0x03) << 3) |
694 (chunk.ptr[i+4] >> 5)];
695 *pos++ = b32digits[chunk.ptr[i+4] & 0x1F];
696 }
697 *pos = '\0';
698 return chunk_create(buf, len * 8 / 5);
699 }
700
701 /**
702 * Described in header.
703 */
704 int chunk_compare(chunk_t a, chunk_t b)
705 {
706 int compare_len = a.len - b.len;
707 int len = (compare_len < 0)? a.len : b.len;
708
709 if (compare_len != 0 || len == 0)
710 {
711 return compare_len;
712 }
713 return memcmp(a.ptr, b.ptr, len);
714 };
715
716
717 /**
718 * Described in header.
719 */
720 bool chunk_increment(chunk_t chunk)
721 {
722 int i;
723
724 for (i = chunk.len - 1; i >= 0; i--)
725 {
726 if (++chunk.ptr[i] != 0)
727 {
728 return FALSE;
729 }
730 }
731 return TRUE;
732 }
733
734 /**
735 * Remove non-printable characters from a chunk.
736 */
737 bool chunk_printable(chunk_t chunk, chunk_t *sane, char replace)
738 {
739 bool printable = TRUE;
740 int i;
741
742 if (sane)
743 {
744 *sane = chunk_clone(chunk);
745 }
746 for (i = 0; i < chunk.len; i++)
747 {
748 if (!isprint(chunk.ptr[i]))
749 {
750 if (sane)
751 {
752 sane->ptr[i] = replace;
753 }
754 printable = FALSE;
755 }
756 }
757 return printable;
758 }
759
760 /**
761 * Helper functions for chunk_mac()
762 */
763 static inline u_int64_t sipget(u_char *in)
764 {
765 u_int64_t v = 0;
766 int i;
767
768 for (i = 0; i < 64; i += 8, ++in)
769 {
770 v |= ((u_int64_t)*in) << i;
771 }
772 return v;
773 }
774
775 static inline u_int64_t siprotate(u_int64_t v, int shift)
776 {
777 return (v << shift) | (v >> (64 - shift));
778 }
779
780 static inline void sipround(u_int64_t *v0, u_int64_t *v1, u_int64_t *v2,
781 u_int64_t *v3)
782 {
783 *v0 += *v1;
784 *v1 = siprotate(*v1, 13);
785 *v1 ^= *v0;
786 *v0 = siprotate(*v0, 32);
787
788 *v2 += *v3;
789 *v3 = siprotate(*v3, 16);
790 *v3 ^= *v2;
791
792 *v2 += *v1;
793 *v1 = siprotate(*v1, 17);
794 *v1 ^= *v2;
795 *v2 = siprotate(*v2, 32);
796
797 *v0 += *v3;
798 *v3 = siprotate(*v3, 21);
799 *v3 ^= *v0;
800 }
801
802 static inline void sipcompress(u_int64_t *v0, u_int64_t *v1, u_int64_t *v2,
803 u_int64_t *v3, u_int64_t m)
804 {
805 *v3 ^= m;
806 sipround(v0, v1, v2, v3);
807 sipround(v0, v1, v2, v3);
808 *v0 ^= m;
809 }
810
811 static inline u_int64_t siplast(size_t len, u_char *pos)
812 {
813 u_int64_t b;
814 int rem = len & 7;
815
816 b = ((u_int64_t)len) << 56;
817 switch (rem)
818 {
819 case 7:
820 b |= ((u_int64_t)pos[6]) << 48;
821 case 6:
822 b |= ((u_int64_t)pos[5]) << 40;
823 case 5:
824 b |= ((u_int64_t)pos[4]) << 32;
825 case 4:
826 b |= ((u_int64_t)pos[3]) << 24;
827 case 3:
828 b |= ((u_int64_t)pos[2]) << 16;
829 case 2:
830 b |= ((u_int64_t)pos[1]) << 8;
831 case 1:
832 b |= ((u_int64_t)pos[0]);
833 break;
834 case 0:
835 break;
836 }
837 return b;
838 }
839
840 /**
841 * Caculate SipHash-2-4 with an optional first block given as argument.
842 */
843 static u_int64_t chunk_mac_inc(chunk_t chunk, u_char *key, u_int64_t m)
844 {
845 u_int64_t v0, v1, v2, v3, k0, k1;
846 size_t len = chunk.len;
847 u_char *pos = chunk.ptr, *end;
848
849 end = chunk.ptr + len - (len % 8);
850
851 k0 = sipget(key);
852 k1 = sipget(key + 8);
853
854 v0 = k0 ^ 0x736f6d6570736575ULL;
855 v1 = k1 ^ 0x646f72616e646f6dULL;
856 v2 = k0 ^ 0x6c7967656e657261ULL;
857 v3 = k1 ^ 0x7465646279746573ULL;
858
859 if (m)
860 {
861 sipcompress(&v0, &v1, &v2, &v3, m);
862 }
863
864 /* compression with c = 2 */
865 for (; pos != end; pos += 8)
866 {
867 m = sipget(pos);
868 sipcompress(&v0, &v1, &v2, &v3, m);
869 }
870 sipcompress(&v0, &v1, &v2, &v3, siplast(len, pos));
871
872 /* finalization with d = 4 */
873 v2 ^= 0xff;
874 sipround(&v0, &v1, &v2, &v3);
875 sipround(&v0, &v1, &v2, &v3);
876 sipround(&v0, &v1, &v2, &v3);
877 sipround(&v0, &v1, &v2, &v3);
878 return v0 ^ v1 ^ v2 ^ v3;
879 }
880
881 /**
882 * Described in header.
883 */
884 u_int64_t chunk_mac(chunk_t chunk, u_char *key)
885 {
886 return chunk_mac_inc(chunk, key, 0);
887 }
888
889 /**
890 * Secret key allocated randomly during first use.
891 */
892 static u_char key[16];
893
894 /**
895 * Static key used in case predictable hash values are required.
896 */
897 static u_char static_key[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
898 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
899
900 /**
901 * Only allocate the key once
902 */
903 static pthread_once_t key_allocated = PTHREAD_ONCE_INIT;
904
905 /**
906 * Allocate a key on first use, we do this manually to avoid dependencies on
907 * plugins.
908 */
909 static void allocate_key()
910 {
911 ssize_t len;
912 size_t done = 0;
913 int fd;
914
915 fd = open("/dev/urandom", O_RDONLY);
916 if (fd >= 0)
917 {
918 while (done < sizeof(key))
919 {
920 len = read(fd, key + done, sizeof(key) - done);
921 if (len < 0)
922 {
923 break;
924 }
925 done += len;
926 }
927 close(fd);
928 }
929 /* on error we use random() to generate the key (better than nothing) */
930 if (done < sizeof(key))
931 {
932 srandom(time(NULL) + getpid());
933 for (; done < sizeof(key); done++)
934 {
935 key[done] = (u_char)random();
936 }
937 }
938 }
939
940 /**
941 * Described in header.
942 */
943 u_int32_t chunk_hash_inc(chunk_t chunk, u_int32_t hash)
944 {
945 pthread_once(&key_allocated, allocate_key);
946 /* we could use a mac of the previous hash, but this is faster */
947 return chunk_mac_inc(chunk, key, ((u_int64_t)hash) << 32 | hash);
948 }
949
950 /**
951 * Described in header.
952 */
953 u_int32_t chunk_hash(chunk_t chunk)
954 {
955 pthread_once(&key_allocated, allocate_key);
956 return chunk_mac(chunk, key);
957 }
958
959 /**
960 * Described in header.
961 */
962 u_int32_t chunk_hash_static_inc(chunk_t chunk, u_int32_t hash)
963 { /* we could use a mac of the previous hash, but this is faster */
964 return chunk_mac_inc(chunk, static_key, ((u_int64_t)hash) << 32 | hash);
965 }
966
967 /**
968 * Described in header.
969 */
970 u_int32_t chunk_hash_static(chunk_t chunk)
971 {
972 return chunk_mac(chunk, static_key);
973 }
974
975 /**
976 * Described in header.
977 */
978 int chunk_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
979 const void *const *args)
980 {
981 chunk_t *chunk = *((chunk_t**)(args[0]));
982 bool first = TRUE;
983 chunk_t copy = *chunk;
984 int written = 0;
985
986 if (!spec->hash && !spec->plus)
987 {
988 u_int chunk_len = chunk->len;
989 const void *new_args[] = {&chunk->ptr, &chunk_len};
990 return mem_printf_hook(data, spec, new_args);
991 }
992
993 while (copy.len > 0)
994 {
995 if (first)
996 {
997 first = FALSE;
998 }
999 else if (!spec->plus)
1000 {
1001 written += print_in_hook(data, ":");
1002 }
1003 written += print_in_hook(data, "%02x", *copy.ptr++);
1004 copy.len--;
1005 }
1006 return written;
1007 }