]> git.saurik.com Git - apple/syslog.git/blob - libsystem_asl.tproj/src/asl_string.c
syslog-356.70.1.tar.gz
[apple/syslog.git] / libsystem_asl.tproj / src / asl_string.c
1 /*
2 * Copyright (c) 2007-2015 Apple Inc. All rights reserved.
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
39 static const char *cvis_7_13 = "abtnvfr";
40
41 /* Forward */
42 asl_string_t *asl_string_append_no_encoding_len(asl_string_t *str, const char *app, size_t copylen);
43
44 asl_string_t *
45 asl_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
59 if (encoding & ASL_STRING_LEN) asl_string_append_no_encoding_len(str, " 0 ", 11);
60 return str;
61 }
62
63 asl_string_t *
64 asl_string_retain(asl_string_t *str)
65 {
66 if (str == NULL) return NULL;
67
68 OSAtomicIncrement32Barrier(&(str->refcount));
69 return str;
70 }
71
72 void
73 asl_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
90 char *
91 asl_string_release_return_bytes(asl_string_t *str)
92 {
93 char *out;
94 if (str == NULL) return NULL;
95
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
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;
111 kern_return_t kstatus = vm_allocate(mach_task_self(), &new, str->bufsize, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
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
129 char *
130 asl_string_bytes(asl_string_t *str)
131 {
132 if (str == NULL) return NULL;
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
141 return str->buf;
142 }
143
144 /* length includes trailing nul */
145 size_t
146 asl_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
154 size_t
155 asl_string_allocated_size(asl_string_t *str)
156 {
157 if (str == NULL) return 0;
158 return str->bufsize;
159 }
160
161 static 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
187 kstatus = vm_allocate(mach_task_self(), &new, newlen, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
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
220 asl_string_t *
221 asl_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++;
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
235 return str;
236 }
237
238 asl_string_t *
239 asl_string_append_no_encoding_len(asl_string_t *str, const char *app, size_t copylen)
240 {
241 size_t len, applen;
242
243 if (str == NULL) return NULL;
244 if (app == NULL) return str;
245
246 applen = copylen;
247 if (applen == 0) applen = strlen(app);
248
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
259 return str;
260 }
261
262 asl_string_t *
263 asl_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
268 static asl_string_t *
269 asl_string_append_internal(asl_string_t *str, const char *app, int encode_space)
270 {
271 uint8_t x, y, z;
272 const uint8_t *s, *p;
273 size_t copylen;
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 {
282 return asl_string_append_no_encoding_len(str, app, 0);
283 }
284 case ASL_ENCODE_SAFE:
285 {
286 /* minor encoding to reduce the likelyhood of spoof attacks */
287 const char *p;
288
289 s = NULL;
290 copylen = 0;
291
292 for (p = app; *p != '\0'; p++)
293 {
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))
302 {
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);
311 }
312 else if (x == 8)
313 {
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);
350 }
351 else
352 {
353 if (s == NULL) s = p;
354 copylen++;
355 }
356 }
357
358 if (copylen > 0) asl_string_append_no_encoding_len(str, s, copylen);
359
360 return str;
361 }
362 case ASL_ENCODE_ASL:
363 {
364 s = NULL;
365 copylen = 0;
366
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 {
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);
387 continue;
388 }
389
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);
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 {
407 if (s == NULL) s = p;
408 copylen++;
409 continue;
410 }
411
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);
420 continue;
421 }
422
423 /* \ is escaped */
424 if ((meta == 0) && (x == 92))
425 {
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);
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 {
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);
449 continue;
450 }
451
452 /* DEL is \^? */
453 if (x == 127)
454 {
455 if (meta == 0)
456 {
457 if (copylen > 0)
458 {
459 asl_string_append_no_encoding_len(str, s, copylen);
460 s = NULL;
461 copylen = 0;
462 }
463
464 asl_string_append_char_no_encoding(str, '\\');
465 }
466
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);
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 {
483 if (copylen > 0)
484 {
485 asl_string_append_no_encoding_len(str, s, copylen);
486 s = NULL;
487 copylen = 0;
488 }
489
490 asl_string_append_char_no_encoding(str, '-');
491 asl_string_append_char_no_encoding(str, x);
492 continue;
493 }
494
495 if (s == NULL) s = p;
496 copylen++;
497
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 {
504 if (copylen > 0)
505 {
506 asl_string_append_no_encoding_len(str, s, copylen);
507 s = NULL;
508 copylen = 0;
509 }
510
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 {
521 if (copylen > 0)
522 {
523 asl_string_append_no_encoding_len(str, s, copylen);
524 s = NULL;
525 copylen = 0;
526 }
527
528 asl_string_append_char_no_encoding(str, '\\');
529 }
530
531 if (copylen > 0)
532 {
533 asl_string_append_no_encoding_len(str, s, copylen);
534 s = NULL;
535 copylen = 0;
536 }
537
538 asl_string_append_char_no_encoding(str, '^');
539 asl_string_append_char_no_encoding(str, 64 + x);
540 continue;
541 }
542
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;
552 }
553
554 return str;
555 }
556 case ASL_ENCODE_XML:
557 {
558 s = NULL;
559 copylen = 0;
560
561 for (p = app; *p != '\0'; p++)
562 {
563 x = *p;
564
565 if (x == '&')
566 {
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);
575 }
576 else if (x == '<')
577 {
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);
586 }
587 else if (x == '>')
588 {
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);
597 }
598 else if (x == '"')
599 {
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);
608 }
609 else if (x == '\'')
610 {
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);
619 }
620 else if (iscntrl(x))
621 {
622 if (copylen > 0)
623 {
624 asl_string_append_no_encoding_len(str, s, copylen);
625 s = NULL;
626 copylen = 0;
627 }
628
629 char tmp[8];
630 snprintf(tmp, sizeof(tmp), "&#x%02hhx;", x);
631 asl_string_append_no_encoding_len(str, tmp, 6);
632 }
633 else
634 {
635 if (s == NULL) s = p;
636 copylen++;
637 }
638 }
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;
648 }
649 default:
650 {
651 return str;
652 }
653 }
654
655 return str;
656 }
657
658 asl_string_t *
659 asl_string_append(asl_string_t *str, const char *app)
660 {
661 return asl_string_append_internal(str, app, 0);
662 }
663
664 asl_string_t *
665 asl_string_append_asl_key(asl_string_t *str, const char *app)
666 {
667 return asl_string_append_internal(str, app, 1);
668 }
669
670 asl_string_t *
671 asl_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';
732 return asl_string_append_no_encoding_len(str, opstr, 0);
733 }
734
735 asl_string_t *
736 asl_string_append_xml_tag(asl_string_t *str, const char *tag, const char *s)
737 {
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, '>');
741 asl_string_append_internal(str, s, 0);
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);
745 return str;
746 }
747