]> git.saurik.com Git - apple/syslog.git/blame - libsystem_asl.tproj/src/asl_string.c
syslog-385.tar.gz
[apple/syslog.git] / libsystem_asl.tproj / src / asl_string.c
CommitLineData
f3df4c03 1/*
5222c21d 2 * Copyright (c) 2007-2015 Apple Inc. All rights reserved.
f3df4c03
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <ctype.h>
25#include <stdlib.h>
26#include <stdio.h>
27#include <asl.h>
28#include <string.h>
29#include <mach/kern_return.h>
30#include <mach/mach_init.h>
31#include <mach/mach_vm.h>
32#include <mach/vm_map.h>
33#include <mach/vm_param.h>
34#include <libkern/OSAtomic.h>
35#include <asl_string.h>
36#include <asl_private.h>
37
38#define ASL_STRING_QUANTUM 256
39static const char *cvis_7_13 = "abtnvfr";
40
5222c21d
A
41/* Forward */
42asl_string_t *asl_string_append_no_encoding_len(asl_string_t *str, const char *app, size_t copylen);
43
f3df4c03
A
44asl_string_t *
45asl_string_new(uint32_t encoding)
46{
47 asl_string_t *str = (asl_string_t *)calloc(1, sizeof(asl_string_t));
48 if (str == NULL) return NULL;
49
50 str->asl_type = ASL_TYPE_STRING;
51 str->refcount = 1;
52
53 str->encoding = encoding;
54 str->delta = ASL_STRING_QUANTUM;
55 if (encoding & ASL_STRING_VM) str->delta = PAGE_SIZE;
56 str->bufsize = 0;
57 str->cursor = 0;
58
5222c21d 59 if (encoding & ASL_STRING_LEN) asl_string_append_no_encoding_len(str, " 0 ", 11);
f3df4c03
A
60 return str;
61}
62
63asl_string_t *
64asl_string_retain(asl_string_t *str)
65{
66 if (str == NULL) return NULL;
67
68 OSAtomicIncrement32Barrier(&(str->refcount));
69 return str;
70}
71
72void
73asl_string_release(asl_string_t *str)
74{
75 if (str == NULL) return;
76 if (OSAtomicDecrement32Barrier(&(str->refcount)) != 0) return;
77
78 if (str->encoding & ASL_STRING_VM)
79 {
80 vm_deallocate(mach_task_self(), (vm_address_t)str->buf, str->bufsize);
81 }
82 else
83 {
84 free(str->buf);
85 }
86
87 free(str);
88}
89
90char *
91asl_string_release_return_bytes(asl_string_t *str)
92{
93 char *out;
94 if (str == NULL) return NULL;
95
5222c21d
A
96 if (str->encoding & ASL_STRING_LEN)
97 {
98 char tmp[11];
99 snprintf(tmp, sizeof(tmp), "%10lu", str->cursor - 10);
100 memcpy(str->buf, tmp, 10);
101 }
102
f3df4c03
A
103 if (OSAtomicDecrement32Barrier(&(str->refcount)) != 0)
104 {
105 /* string is still retained - copy buf */
106 if (str->encoding & ASL_STRING_VM)
107 {
108 if (str->bufsize == 0) return NULL;
109
110 vm_address_t new = 0;
5222c21d 111 kern_return_t kstatus = vm_allocate(mach_task_self(), &new, str->bufsize, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
f3df4c03
A
112 if (kstatus != KERN_SUCCESS) return NULL;
113
114 memcpy((void *)new, str->buf, str->bufsize);
115 return (char *)new;
116 }
117 else
118 {
119 if (str->cursor == 0) return NULL;
120 return strdup(str->buf);
121 }
122 }
123
124 out = str->buf;
125 free(str);
126 return out;
127}
128
129char *
130asl_string_bytes(asl_string_t *str)
131{
132 if (str == NULL) return NULL;
5222c21d
A
133
134 if (str->encoding & ASL_STRING_LEN)
135 {
136 char tmp[11];
137 snprintf(tmp, sizeof(tmp), "%10lu", str->cursor - 10);
138 memcpy(str->buf, tmp, 10);
139 }
140
f3df4c03
A
141 return str->buf;
142}
143
144/* length includes trailing nul */
145size_t
146asl_string_length(asl_string_t *str)
147{
148 if (str == NULL) return 0;
149 if (str->cursor == 0) return 0;
150
151 return str->cursor + 1;
152}
153
154size_t
155asl_string_allocated_size(asl_string_t *str)
156{
157 if (str == NULL) return 0;
158 return str->bufsize;
159}
160
161static int
162_asl_string_grow(asl_string_t *str, size_t len)
163{
164 size_t newlen = 0;
165
166 if (str == NULL) return -1;
167 if (len == 0) return 0;
168
169 if (str->bufsize == 0)
170 {
171 newlen = ((len + str->delta - 1) / str->delta) * str->delta;
172 }
173 else
174 {
175 /* used size is (str->cursor + 1) including tailiing nul */
176 if (len <= (str->bufsize - (str->cursor + 1))) return 0;
177
178 /* really this is ((str->cursor + 1) + len + (str->delta - 1)) */
179 newlen = ((str->cursor + len + str->delta) / str->delta) * str->delta;
180 }
181
182 if (str->encoding & ASL_STRING_VM)
183 {
184 kern_return_t kstatus;
185 vm_address_t new = 0;
186
5222c21d 187 kstatus = vm_allocate(mach_task_self(), &new, newlen, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
f3df4c03
A
188 if (kstatus != KERN_SUCCESS)
189 {
190 new = 0;
191 newlen = 0;
192 return -1;
193 }
194
195 if (str->buf != NULL)
196 {
197 memcpy((void *)new, str->buf, str->bufsize);
198 vm_deallocate(mach_task_self(), (vm_address_t)str->buf, str->bufsize);
199 }
200
201 str->buf = (char *)new;
202 str->bufsize = newlen;
203 }
204 else
205 {
206 str->buf = reallocf(str->buf, newlen);
207 if (str->buf == NULL)
208 {
209 str->cursor = 0;
210 str->bufsize = 0;
211 return -1;
212 }
213
214 str->bufsize = newlen;
215 }
216
217 return 0;
218}
219
220asl_string_t *
221asl_string_append_char_no_encoding(asl_string_t *str, const char c)
222{
223 size_t len;
224
225 if (str == NULL) return NULL;
226
227 len = 1;
228 if (str->bufsize == 0) len++;
f3df4c03
A
229 if (_asl_string_grow(str, len) < 0) return str;
230
231 str->buf[str->cursor] = c;
232 str->cursor++;
233 str->buf[str->cursor] = '\0';
234
f3df4c03
A
235 return str;
236}
237
238asl_string_t *
5222c21d 239asl_string_append_no_encoding_len(asl_string_t *str, const char *app, size_t copylen)
f3df4c03
A
240{
241 size_t len, applen;
242
243 if (str == NULL) return NULL;
244 if (app == NULL) return str;
245
5222c21d
A
246 applen = copylen;
247 if (applen == 0) applen = strlen(app);
248
f3df4c03
A
249 len = applen;
250 if (str->bufsize == 0) len++;
251
252 if (_asl_string_grow(str, len) < 0) return str;
253
254 memcpy(str->buf + str->cursor, app, applen);
255
256 str->cursor += applen;
257 str->buf[str->cursor] = '\0';
258
f3df4c03
A
259 return str;
260}
261
5222c21d
A
262asl_string_t *
263asl_string_append_no_encoding(asl_string_t *str, const char *app)
264{
265 return asl_string_append_no_encoding_len(str, app, 0);
266}
267
f3df4c03
A
268static asl_string_t *
269asl_string_append_internal(asl_string_t *str, const char *app, int encode_space)
270{
5222c21d
A
271 uint8_t x, y, z;
272 const uint8_t *s, *p;
273 size_t copylen;
f3df4c03
A
274
275 if (str == NULL) return NULL;
276 if (app == NULL) return str;
277
278 switch (str->encoding & ASL_ENCODE_MASK)
279 {
280 case ASL_ENCODE_NONE:
281 {
5222c21d 282 return asl_string_append_no_encoding_len(str, app, 0);
f3df4c03
A
283 }
284 case ASL_ENCODE_SAFE:
285 {
286 /* minor encoding to reduce the likelyhood of spoof attacks */
287 const char *p;
288
5222c21d
A
289 s = NULL;
290 copylen = 0;
291
f3df4c03
A
292 for (p = app; *p != '\0'; p++)
293 {
5222c21d
A
294 x = p[0];
295 y = 0;
296 z = 0;
297
298 if (x != 0) y = p[1];
299 if (y != 0) z = p[2];
300
301 if ((x == 10) || (x == 13))
f3df4c03 302 {
5222c21d
A
303 if (copylen > 0)
304 {
305 asl_string_append_no_encoding_len(str, s, copylen);
306 s = NULL;
307 copylen = 0;
308 }
309
310 asl_string_append_no_encoding_len(str, "\n\t", 2);
f3df4c03 311 }
5222c21d 312 else if (x == 8)
f3df4c03 313 {
5222c21d
A
314 if (copylen > 0)
315 {
316 asl_string_append_no_encoding_len(str, s, copylen);
317 s = NULL;
318 copylen = 0;
319 }
320
321 asl_string_append_no_encoding_len(str, "^H", 2);
322 }
323 else if ((x == 0xc2) && (y == 0x85))
324 {
325 p++;
326
327 /* next line - format like newline */
328 if (copylen > 0)
329 {
330 asl_string_append_no_encoding_len(str, s, copylen);
331 s = NULL;
332 copylen = 0;
333 }
334
335 asl_string_append_no_encoding_len(str, "\n\t", 2);
336 }
337 else if ((x == 0xe2) && (y == 0x80) && ((z == 0xa8) || (z == 0xa9)))
338 {
339 p += 3;
340
341 /* line separator or paragraph separator - format like newline */
342 if (copylen > 0)
343 {
344 asl_string_append_no_encoding_len(str, s, copylen);
345 s = NULL;
346 copylen = 0;
347 }
348
349 asl_string_append_no_encoding_len(str, "\n\t", 2);
f3df4c03
A
350 }
351 else
352 {
5222c21d
A
353 if (s == NULL) s = p;
354 copylen++;
f3df4c03
A
355 }
356 }
357
5222c21d
A
358 if (copylen > 0) asl_string_append_no_encoding_len(str, s, copylen);
359
f3df4c03
A
360 return str;
361 }
362 case ASL_ENCODE_ASL:
363 {
5222c21d
A
364 s = NULL;
365 copylen = 0;
366
f3df4c03
A
367 for (p = app; *p != '\0'; p++)
368 {
369 int meta = 0;
370
371 x = *p;
372
373 /* Meta chars get \M prefix */
374 if (x >= 128)
375 {
376 /* except meta-space, which is \240 */
377 if (x == 160)
378 {
5222c21d
A
379 if (copylen > 0)
380 {
381 asl_string_append_no_encoding_len(str, s, copylen);
382 s = NULL;
383 copylen = 0;
384 }
385
386 asl_string_append_no_encoding_len(str, "\\240", 4);
f3df4c03
A
387 continue;
388 }
389
5222c21d
A
390 if (copylen > 0)
391 {
392 asl_string_append_no_encoding_len(str, s, copylen);
393 s = NULL;
394 copylen = 0;
395 }
396
397 asl_string_append_no_encoding_len(str, "\\M", 2);
f3df4c03
A
398 x &= 0x7f;
399 meta = 1;
400 }
401
402 /* space is either ' ' or \s */
403 if (x == 32)
404 {
405 if (encode_space == 0)
406 {
5222c21d
A
407 if (s == NULL) s = p;
408 copylen++;
f3df4c03
A
409 continue;
410 }
411
5222c21d
A
412 if (copylen > 0)
413 {
414 asl_string_append_no_encoding_len(str, s, copylen);
415 s = NULL;
416 copylen = 0;
417 }
418
419 asl_string_append_no_encoding_len(str, "\\s", 2);
f3df4c03
A
420 continue;
421 }
422
423 /* \ is escaped */
424 if ((meta == 0) && (x == 92))
425 {
5222c21d
A
426 if (copylen > 0)
427 {
428 asl_string_append_no_encoding_len(str, s, copylen);
429 s = NULL;
430 copylen = 0;
431 }
432
433 asl_string_append_no_encoding_len(str, "\\\\", 2);
f3df4c03
A
434 continue;
435 }
436
437 /* [ and ] are escaped in ASL encoding */
438 if ((str->encoding & ASL_ENCODE_ASL) && (meta == 0) && ((*p == 91) || (*p == 93)))
439 {
5222c21d
A
440 if (copylen > 0)
441 {
442 asl_string_append_no_encoding_len(str, s, copylen);
443 s = NULL;
444 copylen = 0;
445 }
446
447 if (*p == '[') asl_string_append_no_encoding_len(str, "\\[", 2);
448 else asl_string_append_no_encoding_len(str, "\\]", 2);
f3df4c03
A
449 continue;
450 }
451
452 /* DEL is \^? */
453 if (x == 127)
454 {
455 if (meta == 0)
456 {
5222c21d
A
457 if (copylen > 0)
458 {
459 asl_string_append_no_encoding_len(str, s, copylen);
460 s = NULL;
461 copylen = 0;
462 }
463
f3df4c03
A
464 asl_string_append_char_no_encoding(str, '\\');
465 }
466
5222c21d
A
467 if (copylen > 0)
468 {
469 asl_string_append_no_encoding_len(str, s, copylen);
470 s = NULL;
471 copylen = 0;
472 }
473
474 asl_string_append_no_encoding_len(str, "^?", 2);
f3df4c03
A
475 continue;
476 }
477
478 /* 33-126 are printable (add a '-' prefix for meta) */
479 if ((x >= 33) && (x <= 126))
480 {
481 if (meta == 1)
482 {
5222c21d
A
483 if (copylen > 0)
484 {
485 asl_string_append_no_encoding_len(str, s, copylen);
486 s = NULL;
487 copylen = 0;
488 }
489
f3df4c03 490 asl_string_append_char_no_encoding(str, '-');
5222c21d
A
491 asl_string_append_char_no_encoding(str, x);
492 continue;
f3df4c03
A
493 }
494
5222c21d
A
495 if (s == NULL) s = p;
496 copylen++;
497
f3df4c03
A
498 continue;
499 }
500
501 /* non-meta BEL, BS, HT, NL, VT, NP, CR (7-13) are \a, \b, \t, \n, \v, \f, and \r */
502 if ((meta == 0) && (x >= 7) && (x <= 13))
503 {
5222c21d
A
504 if (copylen > 0)
505 {
506 asl_string_append_no_encoding_len(str, s, copylen);
507 s = NULL;
508 copylen = 0;
509 }
510
f3df4c03
A
511 asl_string_append_char_no_encoding(str, '\\');
512 asl_string_append_char_no_encoding(str, cvis_7_13[x - 7]);
513 continue;
514 }
515
516 /* 0 - 31 are ^@ - ^_ (non-meta get a leading \) */
517 if (x <= 31)
518 {
519 if (meta == 0)
520 {
5222c21d
A
521 if (copylen > 0)
522 {
523 asl_string_append_no_encoding_len(str, s, copylen);
524 s = NULL;
525 copylen = 0;
526 }
527
f3df4c03
A
528 asl_string_append_char_no_encoding(str, '\\');
529 }
530
5222c21d
A
531 if (copylen > 0)
532 {
533 asl_string_append_no_encoding_len(str, s, copylen);
534 s = NULL;
535 copylen = 0;
536 }
537
f3df4c03
A
538 asl_string_append_char_no_encoding(str, '^');
539 asl_string_append_char_no_encoding(str, 64 + x);
540 continue;
541 }
542
5222c21d
A
543 if (s == NULL) s = p;
544 copylen++;
545 }
546
547 if (copylen > 0)
548 {
549 asl_string_append_no_encoding_len(str, s, copylen);
550 s = NULL;
551 copylen = 0;
f3df4c03
A
552 }
553
554 return str;
555 }
556 case ASL_ENCODE_XML:
557 {
5222c21d
A
558 s = NULL;
559 copylen = 0;
560
f3df4c03
A
561 for (p = app; *p != '\0'; p++)
562 {
563 x = *p;
564
565 if (x == '&')
566 {
5222c21d
A
567 if (copylen > 0)
568 {
569 asl_string_append_no_encoding_len(str, s, copylen);
570 s = NULL;
571 copylen = 0;
572 }
573
574 asl_string_append_no_encoding_len(str, "&amp;", 5);
f3df4c03
A
575 }
576 else if (x == '<')
577 {
5222c21d
A
578 if (copylen > 0)
579 {
580 asl_string_append_no_encoding_len(str, s, copylen);
581 s = NULL;
582 copylen = 0;
583 }
584
585 asl_string_append_no_encoding_len(str, "&lt;", 4);
f3df4c03
A
586 }
587 else if (x == '>')
588 {
5222c21d
A
589 if (copylen > 0)
590 {
591 asl_string_append_no_encoding_len(str, s, copylen);
592 s = NULL;
593 copylen = 0;
594 }
595
596 asl_string_append_no_encoding_len(str, "&gt;", 4);
f3df4c03
A
597 }
598 else if (x == '"')
599 {
5222c21d
A
600 if (copylen > 0)
601 {
602 asl_string_append_no_encoding_len(str, s, copylen);
603 s = NULL;
604 copylen = 0;
605 }
606
607 asl_string_append_no_encoding_len(str, "&quot;", 6);
f3df4c03
A
608 }
609 else if (x == '\'')
610 {
5222c21d
A
611 if (copylen > 0)
612 {
613 asl_string_append_no_encoding_len(str, s, copylen);
614 s = NULL;
615 copylen = 0;
616 }
617
618 asl_string_append_no_encoding_len(str, "&apos;", 6);
f3df4c03
A
619 }
620 else if (iscntrl(x))
621 {
5222c21d
A
622 if (copylen > 0)
623 {
624 asl_string_append_no_encoding_len(str, s, copylen);
625 s = NULL;
626 copylen = 0;
627 }
628
f3df4c03
A
629 char tmp[8];
630 snprintf(tmp, sizeof(tmp), "&#x%02hhx;", x);
5222c21d 631 asl_string_append_no_encoding_len(str, tmp, 6);
f3df4c03
A
632 }
633 else
634 {
5222c21d
A
635 if (s == NULL) s = p;
636 copylen++;
f3df4c03
A
637 }
638 }
5222c21d
A
639
640 if (copylen > 0)
641 {
642 asl_string_append_no_encoding_len(str, s, copylen);
643 s = NULL;
644 copylen = 0;
645 }
646
647 return str;
f3df4c03
A
648 }
649 default:
650 {
651 return str;
652 }
653 }
654
655 return str;
656}
657
658asl_string_t *
659asl_string_append(asl_string_t *str, const char *app)
660{
661 return asl_string_append_internal(str, app, 0);
662}
663
664asl_string_t *
665asl_string_append_asl_key(asl_string_t *str, const char *app)
666{
667 return asl_string_append_internal(str, app, 1);
668}
669
670asl_string_t *
671asl_string_append_op(asl_string_t *str, uint32_t op)
672{
673 char opstr[8];
674 uint32_t i;
675
676 if (str == NULL) return NULL;
677
678 if (op == ASL_QUERY_OP_NULL)
679 {
680 return asl_string_append_char_no_encoding(str, '.');
681 }
682
683 i = 0;
684 if (op & ASL_QUERY_OP_CASEFOLD) opstr[i++] = 'C';
685
686 if (op & ASL_QUERY_OP_REGEX) opstr[i++] = 'R';
687
688 if (op & ASL_QUERY_OP_NUMERIC) opstr[i++] = 'N';
689
690 if (op & ASL_QUERY_OP_PREFIX)
691 {
692 if (op & ASL_QUERY_OP_SUFFIX) opstr[i++] = 'S';
693 else opstr[i++] = 'A';
694 }
695 if (op & ASL_QUERY_OP_SUFFIX) opstr[i++] = 'Z';
696
697 switch (op & ASL_QUERY_OP_TRUE)
698 {
699 case ASL_QUERY_OP_EQUAL:
700 opstr[i++] = '=';
701 break;
702 case ASL_QUERY_OP_GREATER:
703 opstr[i++] = '>';
704 break;
705 case ASL_QUERY_OP_GREATER_EQUAL:
706 opstr[i++] = '>';
707 opstr[i++] = '=';
708 break;
709 case ASL_QUERY_OP_LESS:
710 opstr[i++] = '<';
711 break;
712 case ASL_QUERY_OP_LESS_EQUAL:
713 opstr[i++] = '<';
714 opstr[i++] = '=';
715 break;
716 case ASL_QUERY_OP_NOT_EQUAL:
717 opstr[i++] = '!';
718 break;
719 case ASL_QUERY_OP_TRUE:
720 opstr[i++] = 'T';
721 break;
722 default:
723 break;
724 }
725
726 if (i == 0)
727 {
728 return asl_string_append_char_no_encoding(str, '.');
729 }
730
731 opstr[i] = '\0';
5222c21d 732 return asl_string_append_no_encoding_len(str, opstr, 0);
f3df4c03
A
733}
734
735asl_string_t *
736asl_string_append_xml_tag(asl_string_t *str, const char *tag, const char *s)
737{
5222c21d
A
738 asl_string_append_no_encoding_len(str, "\t\t<", 3);
739 asl_string_append_no_encoding_len(str, tag, 0);
740 asl_string_append_char_no_encoding(str, '>');
f3df4c03 741 asl_string_append_internal(str, s, 0);
5222c21d
A
742 asl_string_append_no_encoding_len(str, "</", 2);
743 asl_string_append_no_encoding_len(str, tag, 0);
744 asl_string_append_no_encoding_len(str, ">\n", 2);
f3df4c03
A
745 return str;
746}
747