]> git.saurik.com Git - apple/syslog.git/blame - libsystem_asl.tproj/src/asl_string.c
syslog-267.tar.gz
[apple/syslog.git] / libsystem_asl.tproj / src / asl_string.c
CommitLineData
f3df4c03
A
1/*
2 * Copyright (c) 2007-2013 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
39static const char *cvis_7_13 = "abtnvfr";
40
41asl_string_t *
42asl_string_new(uint32_t encoding)
43{
44 asl_string_t *str = (asl_string_t *)calloc(1, sizeof(asl_string_t));
45 if (str == NULL) return NULL;
46
47 str->asl_type = ASL_TYPE_STRING;
48 str->refcount = 1;
49
50 str->encoding = encoding;
51 str->delta = ASL_STRING_QUANTUM;
52 if (encoding & ASL_STRING_VM) str->delta = PAGE_SIZE;
53 str->bufsize = 0;
54 str->cursor = 0;
55
56 if (encoding & ASL_STRING_LEN) asl_string_append_no_encoding(str, " 0 ");
57 return str;
58}
59
60asl_string_t *
61asl_string_retain(asl_string_t *str)
62{
63 if (str == NULL) return NULL;
64
65 OSAtomicIncrement32Barrier(&(str->refcount));
66 return str;
67}
68
69void
70asl_string_release(asl_string_t *str)
71{
72 if (str == NULL) return;
73 if (OSAtomicDecrement32Barrier(&(str->refcount)) != 0) return;
74
75 if (str->encoding & ASL_STRING_VM)
76 {
77 vm_deallocate(mach_task_self(), (vm_address_t)str->buf, str->bufsize);
78 }
79 else
80 {
81 free(str->buf);
82 }
83
84 free(str);
85}
86
87char *
88asl_string_release_return_bytes(asl_string_t *str)
89{
90 char *out;
91 if (str == NULL) return NULL;
92
93 if (OSAtomicDecrement32Barrier(&(str->refcount)) != 0)
94 {
95 /* string is still retained - copy buf */
96 if (str->encoding & ASL_STRING_VM)
97 {
98 if (str->bufsize == 0) return NULL;
99
100 vm_address_t new = 0;
101 kern_return_t kstatus = vm_allocate(mach_task_self(), &new, str->bufsize, TRUE);
102 if (kstatus != KERN_SUCCESS) return NULL;
103
104 memcpy((void *)new, str->buf, str->bufsize);
105 return (char *)new;
106 }
107 else
108 {
109 if (str->cursor == 0) return NULL;
110 return strdup(str->buf);
111 }
112 }
113
114 out = str->buf;
115 free(str);
116 return out;
117}
118
119char *
120asl_string_bytes(asl_string_t *str)
121{
122 if (str == NULL) return NULL;
123 return str->buf;
124}
125
126/* length includes trailing nul */
127size_t
128asl_string_length(asl_string_t *str)
129{
130 if (str == NULL) return 0;
131 if (str->cursor == 0) return 0;
132
133 return str->cursor + 1;
134}
135
136size_t
137asl_string_allocated_size(asl_string_t *str)
138{
139 if (str == NULL) return 0;
140 return str->bufsize;
141}
142
143static int
144_asl_string_grow(asl_string_t *str, size_t len)
145{
146 size_t newlen = 0;
147
148 if (str == NULL) return -1;
149 if (len == 0) return 0;
150
151 if (str->bufsize == 0)
152 {
153 newlen = ((len + str->delta - 1) / str->delta) * str->delta;
154 }
155 else
156 {
157 /* used size is (str->cursor + 1) including tailiing nul */
158 if (len <= (str->bufsize - (str->cursor + 1))) return 0;
159
160 /* really this is ((str->cursor + 1) + len + (str->delta - 1)) */
161 newlen = ((str->cursor + len + str->delta) / str->delta) * str->delta;
162 }
163
164 if (str->encoding & ASL_STRING_VM)
165 {
166 kern_return_t kstatus;
167 vm_address_t new = 0;
168
169 kstatus = vm_allocate(mach_task_self(), &new, newlen, TRUE);
170 if (kstatus != KERN_SUCCESS)
171 {
172 new = 0;
173 newlen = 0;
174 return -1;
175 }
176
177 if (str->buf != NULL)
178 {
179 memcpy((void *)new, str->buf, str->bufsize);
180 vm_deallocate(mach_task_self(), (vm_address_t)str->buf, str->bufsize);
181 }
182
183 str->buf = (char *)new;
184 str->bufsize = newlen;
185 }
186 else
187 {
188 str->buf = reallocf(str->buf, newlen);
189 if (str->buf == NULL)
190 {
191 str->cursor = 0;
192 str->bufsize = 0;
193 return -1;
194 }
195
196 str->bufsize = newlen;
197 }
198
199 return 0;
200}
201
202asl_string_t *
203asl_string_append_char_no_encoding(asl_string_t *str, const char c)
204{
205 size_t len;
206
207 if (str == NULL) return NULL;
208
209 len = 1;
210 if (str->bufsize == 0) len++;
211
212 if (_asl_string_grow(str, len) < 0) return str;
213
214 str->buf[str->cursor] = c;
215 str->cursor++;
216 str->buf[str->cursor] = '\0';
217
218 if (str->encoding & ASL_STRING_LEN)
219 {
220 char tmp[11];
221 snprintf(tmp, sizeof(tmp), "%10lu", str->cursor - 10);
222 memcpy(str->buf, tmp, 10);
223 }
224
225 return str;
226}
227
228asl_string_t *
229asl_string_append_no_encoding(asl_string_t *str, const char *app)
230{
231 size_t len, applen;
232
233 if (str == NULL) return NULL;
234 if (app == NULL) return str;
235
236 applen = strlen(app);
237 len = applen;
238 if (str->bufsize == 0) len++;
239
240 if (_asl_string_grow(str, len) < 0) return str;
241
242 memcpy(str->buf + str->cursor, app, applen);
243
244 str->cursor += applen;
245 str->buf[str->cursor] = '\0';
246
247 if (str->encoding & ASL_STRING_LEN)
248 {
249 char tmp[11];
250 snprintf(tmp, sizeof(tmp), "%10lu", str->cursor - 10);
251 memcpy(str->buf, tmp, 10);
252 }
253
254 return str;
255}
256
257static asl_string_t *
258asl_string_append_internal(asl_string_t *str, const char *app, int encode_space)
259{
260 uint8_t x;
261 const char *p;
262
263 if (str == NULL) return NULL;
264 if (app == NULL) return str;
265
266 switch (str->encoding & ASL_ENCODE_MASK)
267 {
268 case ASL_ENCODE_NONE:
269 {
270 return asl_string_append_no_encoding(str, app);
271 }
272 case ASL_ENCODE_SAFE:
273 {
274 /* minor encoding to reduce the likelyhood of spoof attacks */
275 const char *p;
276
277 for (p = app; *p != '\0'; p++)
278 {
279 if ((*p == 10) || (*p == 13))
280 {
281 asl_string_append_no_encoding(str, "\n\t");
282 }
283 else if (*p == 8)
284 {
285 asl_string_append_no_encoding(str, "^H");
286 }
287 else
288 {
289 asl_string_append_char_no_encoding(str, *p);
290 }
291 }
292
293 return str;
294 }
295 case ASL_ENCODE_ASL:
296 {
297 for (p = app; *p != '\0'; p++)
298 {
299 int meta = 0;
300
301 x = *p;
302
303 /* Meta chars get \M prefix */
304 if (x >= 128)
305 {
306 /* except meta-space, which is \240 */
307 if (x == 160)
308 {
309 asl_string_append_no_encoding(str, "\\240");
310 continue;
311 }
312
313 asl_string_append_no_encoding(str, "\\M");
314 x &= 0x7f;
315 meta = 1;
316 }
317
318 /* space is either ' ' or \s */
319 if (x == 32)
320 {
321 if (encode_space == 0)
322 {
323 asl_string_append_char_no_encoding(str, ' ');
324 continue;
325 }
326
327 asl_string_append_no_encoding(str, "\\s");
328 continue;
329 }
330
331 /* \ is escaped */
332 if ((meta == 0) && (x == 92))
333 {
334 asl_string_append_no_encoding(str, "\\\\");
335 continue;
336 }
337
338 /* [ and ] are escaped in ASL encoding */
339 if ((str->encoding & ASL_ENCODE_ASL) && (meta == 0) && ((*p == 91) || (*p == 93)))
340 {
341 if (*p == '[') asl_string_append_no_encoding(str, "\\[");
342 else asl_string_append_no_encoding(str, "\\]");
343 continue;
344 }
345
346 /* DEL is \^? */
347 if (x == 127)
348 {
349 if (meta == 0)
350 {
351 asl_string_append_char_no_encoding(str, '\\');
352 }
353
354 asl_string_append_no_encoding(str, "^?");
355 continue;
356 }
357
358 /* 33-126 are printable (add a '-' prefix for meta) */
359 if ((x >= 33) && (x <= 126))
360 {
361 if (meta == 1)
362 {
363 asl_string_append_char_no_encoding(str, '-');
364 }
365
366 asl_string_append_char_no_encoding(str, x);
367 continue;
368 }
369
370 /* non-meta BEL, BS, HT, NL, VT, NP, CR (7-13) are \a, \b, \t, \n, \v, \f, and \r */
371 if ((meta == 0) && (x >= 7) && (x <= 13))
372 {
373 asl_string_append_char_no_encoding(str, '\\');
374 asl_string_append_char_no_encoding(str, cvis_7_13[x - 7]);
375 continue;
376 }
377
378 /* 0 - 31 are ^@ - ^_ (non-meta get a leading \) */
379 if (x <= 31)
380 {
381 if (meta == 0)
382 {
383 asl_string_append_char_no_encoding(str, '\\');
384 }
385
386 asl_string_append_char_no_encoding(str, '^');
387 asl_string_append_char_no_encoding(str, 64 + x);
388 continue;
389 }
390
391 asl_string_append_char_no_encoding(str, x);
392 }
393
394 return str;
395 }
396 case ASL_ENCODE_XML:
397 {
398 for (p = app; *p != '\0'; p++)
399 {
400 x = *p;
401
402 if (x == '&')
403 {
404 asl_string_append_no_encoding(str, "&amp;");
405 }
406 else if (x == '<')
407 {
408 asl_string_append_no_encoding(str, "&lt;");
409 }
410 else if (x == '>')
411 {
412 asl_string_append_no_encoding(str, "&gt;");
413 }
414 else if (x == '"')
415 {
416 asl_string_append_no_encoding(str, "&quot;");
417 }
418 else if (x == '\'')
419 {
420 asl_string_append_no_encoding(str, "&apos;");
421 }
422 else if (iscntrl(x))
423 {
424 char tmp[8];
425 snprintf(tmp, sizeof(tmp), "&#x%02hhx;", x);
426 asl_string_append_no_encoding(str, tmp);
427 }
428 else
429 {
430 asl_string_append_char_no_encoding(str, x);
431 }
432 }
433 }
434 default:
435 {
436 return str;
437 }
438 }
439
440 return str;
441}
442
443asl_string_t *
444asl_string_append(asl_string_t *str, const char *app)
445{
446 return asl_string_append_internal(str, app, 0);
447}
448
449asl_string_t *
450asl_string_append_asl_key(asl_string_t *str, const char *app)
451{
452 return asl_string_append_internal(str, app, 1);
453}
454
455asl_string_t *
456asl_string_append_op(asl_string_t *str, uint32_t op)
457{
458 char opstr[8];
459 uint32_t i;
460
461 if (str == NULL) return NULL;
462
463 if (op == ASL_QUERY_OP_NULL)
464 {
465 return asl_string_append_char_no_encoding(str, '.');
466 }
467
468 i = 0;
469 if (op & ASL_QUERY_OP_CASEFOLD) opstr[i++] = 'C';
470
471 if (op & ASL_QUERY_OP_REGEX) opstr[i++] = 'R';
472
473 if (op & ASL_QUERY_OP_NUMERIC) opstr[i++] = 'N';
474
475 if (op & ASL_QUERY_OP_PREFIX)
476 {
477 if (op & ASL_QUERY_OP_SUFFIX) opstr[i++] = 'S';
478 else opstr[i++] = 'A';
479 }
480 if (op & ASL_QUERY_OP_SUFFIX) opstr[i++] = 'Z';
481
482 switch (op & ASL_QUERY_OP_TRUE)
483 {
484 case ASL_QUERY_OP_EQUAL:
485 opstr[i++] = '=';
486 break;
487 case ASL_QUERY_OP_GREATER:
488 opstr[i++] = '>';
489 break;
490 case ASL_QUERY_OP_GREATER_EQUAL:
491 opstr[i++] = '>';
492 opstr[i++] = '=';
493 break;
494 case ASL_QUERY_OP_LESS:
495 opstr[i++] = '<';
496 break;
497 case ASL_QUERY_OP_LESS_EQUAL:
498 opstr[i++] = '<';
499 opstr[i++] = '=';
500 break;
501 case ASL_QUERY_OP_NOT_EQUAL:
502 opstr[i++] = '!';
503 break;
504 case ASL_QUERY_OP_TRUE:
505 opstr[i++] = 'T';
506 break;
507 default:
508 break;
509 }
510
511 if (i == 0)
512 {
513 return asl_string_append_char_no_encoding(str, '.');
514 }
515
516 opstr[i] = '\0';
517 return asl_string_append_no_encoding(str, opstr);
518}
519
520asl_string_t *
521asl_string_append_xml_tag(asl_string_t *str, const char *tag, const char *s)
522{
523 asl_string_append_no_encoding(str, "\t\t<");
524 asl_string_append_no_encoding(str, tag);
525 asl_string_append_no_encoding(str, ">");
526 asl_string_append_internal(str, s, 0);
527 asl_string_append_no_encoding(str, "</");
528 asl_string_append_no_encoding(str, tag);
529 asl_string_append_no_encoding(str, ">\n");
530 return str;
531}
532