2 * Copyright (c) 2007-2011 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
27 #include <asl_private.h>
29 #include <membership.h>
31 #include <libkern/OSAtomic.h>
33 #include <mach/kern_return.h>
34 #include <mach/mach_init.h>
35 #include <mach/mach_vm.h>
36 #include <mach/vm_map.h>
37 #include <mach/vm_param.h>
39 #define ASL_STRING_QUANTUM 256
40 static const char *cvis_7_13
= "abtnvfr";
43 * Message ID generation
45 static uint64_t _asl_core_msg_next_id
= 1;
46 static pthread_mutex_t core_lock
= PTHREAD_MUTEX_INITIALIZER
;
48 #define mix(a, b, c) \
50 a -= b; a -= c; a ^= (c>>13); \
51 b -= c; b -= a; b ^= (a<< 8); \
52 c -= a; c -= b; c ^= (b>>13); \
53 a -= b; a -= c; a ^= (c>>12); \
54 b -= c; b -= a; b ^= (a<<16); \
55 c -= a; c -= b; c ^= (b>> 5); \
56 a -= b; a -= c; a ^= (c>> 3); \
57 b -= c; b -= a; b ^= (a<<10); \
58 c -= a; c -= b; c ^= (b>>15); \
62 * Hash is used to improve string search.
65 asl_core_string_hash(const char *s
, uint32_t inlen
)
67 uint32_t a
, b
, c
, l
, len
;
69 if (s
== NULL
) return 0;
74 if (s
[0] == '\0') return 0;
84 a
+= (s
[0] + ((uint32_t)s
[1]<<8) + ((uint32_t)s
[ 2]<<16) + ((uint32_t)s
[ 3]<<24));
85 b
+= (s
[4] + ((uint32_t)s
[5]<<8) + ((uint32_t)s
[ 6]<<16) + ((uint32_t)s
[ 7]<<24));
86 c
+= (s
[8] + ((uint32_t)s
[9]<<8) + ((uint32_t)s
[10]<<16) + ((uint32_t)s
[11]<<24));
97 case 11: c
+= ((uint32_t)s
[10]<<24);
98 case 10: c
+= ((uint32_t)s
[9]<<16);
99 case 9 : c
+= ((uint32_t)s
[8]<<8);
101 case 8 : b
+= ((uint32_t)s
[7]<<24);
102 case 7 : b
+= ((uint32_t)s
[6]<<16);
103 case 6 : b
+= ((uint32_t)s
[5]<<8);
106 case 4 : a
+= ((uint32_t)s
[3]<<24);
107 case 3 : a
+= ((uint32_t)s
[2]<<16);
108 case 2 : a
+= ((uint32_t)s
[1]<<8);
119 asl_core_error(uint32_t code
)
123 case ASL_STATUS_OK
: return "Operation Succeeded";
124 case ASL_STATUS_INVALID_ARG
: return "Invalid Argument";
125 case ASL_STATUS_INVALID_STORE
: return "Invalid Data Store";
126 case ASL_STATUS_INVALID_STRING
: return "Invalid String";
127 case ASL_STATUS_INVALID_ID
: return "Invalid ID Number";
128 case ASL_STATUS_INVALID_MESSAGE
: return "Invalid Message";
129 case ASL_STATUS_NOT_FOUND
: return "Not Found";
130 case ASL_STATUS_READ_FAILED
: return "Read Operation Failed";
131 case ASL_STATUS_WRITE_FAILED
: return "Write Operation Failed";
132 case ASL_STATUS_NO_MEMORY
: return "System Memory Allocation Failed";
133 case ASL_STATUS_ACCESS_DENIED
: return "Access Denied";
134 case ASL_STATUS_READ_ONLY
: return "Read Only Access";
135 case ASL_STATUS_WRITE_ONLY
: return "Write Only Access";
136 case ASL_STATUS_MATCH_FAILED
: return "Match Failed";
137 case ASL_STATUS_NO_RECORDS
: return "No More Records";
140 return "Operation Failed";
144 asl_core_check_user_access(int32_t msgu
, int32_t readu
)
146 /* -1 means anyone may read */
147 if (msgu
== -1) return ASL_STATUS_OK
;
149 /* Check for exact match */
150 if (msgu
== readu
) return ASL_STATUS_OK
;
152 return ASL_STATUS_ACCESS_DENIED
;
156 asl_core_check_group_access(int32_t msgg
, int32_t readu
, int32_t readg
)
161 /* -1 means anyone may read */
162 if (msgg
== -1) return ASL_STATUS_OK
;
164 /* Check for exact match */
165 if (msgg
== readg
) return ASL_STATUS_OK
;
167 /* Check if user (u) is in read group (msgg) */
168 mbr_uid_to_uuid(readu
, uu
);
169 mbr_gid_to_uuid(msgg
, gu
);
172 mbr_check_membership(uu
, gu
, &check
);
173 if (check
!= 0) return ASL_STATUS_OK
;
175 return ASL_STATUS_ACCESS_DENIED
;
179 asl_core_check_access(int32_t msgu
, int32_t msgg
, int32_t readu
, int32_t readg
, uint16_t flags
)
183 /* root (uid 0) may always read */
184 if (readu
== 0) return ASL_STATUS_OK
;
186 uset
= flags
& ASL_MSG_FLAG_READ_UID_SET
;
187 gset
= flags
& ASL_MSG_FLAG_READ_GID_SET
;
189 /* if no access controls are set, anyone may read */
190 if ((uset
| gset
) == 0) return ASL_STATUS_OK
;
192 /* if only uid is set, then access is only by uid match */
193 if ((uset
!= 0) && (gset
== 0)) return asl_core_check_user_access(msgu
, readu
);
195 /* if only gid is set, then access is only by gid match */
196 if ((uset
== 0) && (gset
!= 0)) return asl_core_check_group_access(msgg
, readu
, readg
);
198 /* both uid and gid are set - check user, then group */
199 if ((asl_core_check_user_access(msgu
, readu
)) == ASL_STATUS_OK
) return ASL_STATUS_OK
;
200 return asl_core_check_group_access(msgg
, readu
, readg
);
204 asl_core_htonq(uint64_t n
)
206 #ifdef __BIG_ENDIAN__
218 x
.l
[0] = htonl(x
.l
[1]);
226 asl_core_ntohq(uint64_t n
)
228 #ifdef __BIG_ENDIAN__
240 x
.l
[0] = ntohl(x
.l
[1]);
248 asl_core_new_msg_id(uint64_t start
)
252 pthread_mutex_lock(&core_lock
);
254 if (start
!= 0) _asl_core_msg_next_id
= start
;
256 out
= _asl_core_msg_next_id
;
257 _asl_core_msg_next_id
++;
259 pthread_mutex_unlock(&core_lock
);
265 * asl_core_encode_buffer
266 * encode arbitrary data as a C string without embedded zero (nul) characters
268 * The routine computes a histogram of the input buffer and finds
269 * the two least frequently used non-nul chars (L[0] and L[1]).
271 * L[0] is used to stand in for nul.
272 * L[1] is used as the escape character.
273 * Occurrences of nul in the data are encoded as L[0]
274 * Occurrences of L[0] in the data are encoded as the sequence L[1] 1.
275 * Occurrences of L[1] in the data are encoded as the sequence L[1] 2.
277 * The output string is preceded by L[0] L[1], and is nul terminated.
278 * The output length is 2 + n + N(L[0]) + N(L[1]) + 1
279 * where N(x) is the number of occurrences of x in the input string.
280 * The worst case occurs when all characters are equally frequent,
281 * In that case the output size will less that 1% larger than the input.
284 asl_core_encode_buffer(const char *in
, uint32_t len
)
287 uint32_t i
, j
, k
, outlen
, breakit
, min
, hist
[256];
288 uint32_t lfu
[2], save
[2];
291 if (in
== NULL
) return NULL
;
292 if (len
== 0) return NULL
;
294 memset(hist
, 0, sizeof(hist
));
298 for (i
= 0; i
< len
; i
++)
304 for (j
= 0; j
< 2; j
++)
309 for (i
= 2; i
< 256; i
++)
317 * Stop if there are no occurances or character i in the input.
318 * The minimum will never be less than zero.
323 * When looking for the second least frequently used character,
324 * stop scanning if we hit the same minimum as we saw in the first
325 * pass. There will be no smaller values.
327 if ((j
== 1) && (min
== save
[0])) break;
331 save
[j
] = hist
[lfu
[j
]];
332 hist
[lfu
[j
]] = (uint32_t)-1;
335 outlen
= 2 + len
+ save
[0] + save
[1] + 1;
337 str
= malloc(outlen
);
338 if (str
== NULL
) return NULL
;
340 str
[outlen
- 1] = '\0';
347 for (i
= 0; i
< len
; i
++)
357 for (k
= 0; (k
< 2) && (breakit
== 0); k
++)
367 if (breakit
== 1) continue;
376 * asl_core_decode_buffer
377 * decode a string produced by asl_encode_buffer to recreate the original data
380 asl_core_decode_buffer(const char *in
, char **buf
, uint32_t *len
)
383 uint32_t i
, j
, n
, outlen
;
387 if (buf
== NULL
) return -1;
388 if (len
== NULL
) return -1;
395 /* strip trailing nul */
398 /* determine output length and check for invalid input */
399 for (i
= 2; i
< n
; i
++)
405 if (i
== n
) return -1;
408 if ((v
< 1) || (v
> 2)) return -1;
415 if (outlen
== 0) return -1;
417 out
= malloc(outlen
);
418 if (out
== NULL
) return -1;
421 for (i
= 2; i
< n
; i
++)
428 else if (v
== lfu
[1])
432 out
[j
++] = lfu
[v
- 1];
442 /* asl_string_t support */
445 asl_string_new(uint32_t encoding
)
447 asl_string_t
*str
= (asl_string_t
*)calloc(1, sizeof(asl_string_t
));
448 if (str
== NULL
) return NULL
;
450 str
->encoding
= encoding
;
451 str
->delta
= ASL_STRING_QUANTUM
;
452 if (encoding
& ASL_STRING_VM
) str
->delta
= PAGE_SIZE
;
456 if (encoding
& ASL_STRING_LEN
) asl_string_append_no_encoding(str
, " 0 ");
461 asl_string_free(asl_string_t
*str
)
463 if (str
== NULL
) return;
465 if (str
->encoding
& ASL_STRING_VM
)
467 vm_deallocate(mach_task_self(), (vm_address_t
)str
->buf
, str
->bufsize
);
478 asl_string_free_return_bytes(asl_string_t
*str
)
481 if (str
== NULL
) return NULL
;
489 asl_string_bytes(asl_string_t
*str
)
491 if (str
== NULL
) return NULL
;
495 /* length includes trailing nul */
497 asl_string_length(asl_string_t
*str
)
499 if (str
== NULL
) return 0;
500 if (str
->cursor
== 0) return 0;
502 return str
->cursor
+ 1;
506 asl_string_allocated_size(asl_string_t
*str
)
508 if (str
== NULL
) return 0;
513 _asl_string_grow(asl_string_t
*str
, size_t len
)
517 if (str
== NULL
) return -1;
518 if (len
== 0) return 0;
520 if (str
->bufsize
== 0)
522 newlen
= ((len
+ str
->delta
- 1) / str
->delta
) * str
->delta
;
526 /* used size is (str->cursor + 1) including tailiing nul */
527 if (len
<= (str
->bufsize
- (str
->cursor
+ 1))) return 0;
529 /* really this is ((str->cursor + 1) + len + (str->delta - 1)) */
530 newlen
= ((str
->cursor
+ len
+ str
->delta
) / str
->delta
) * str
->delta
;
533 if (str
->encoding
& ASL_STRING_VM
)
535 kern_return_t kstatus
;
536 vm_address_t
new = 0;
538 kstatus
= vm_allocate(mach_task_self(), &new, newlen
, TRUE
);
539 if (kstatus
!= KERN_SUCCESS
)
546 if (str
->buf
!= NULL
)
548 memcpy((void *)new, str
->buf
, str
->bufsize
);
549 vm_deallocate(mach_task_self(), (vm_address_t
)str
->buf
, str
->bufsize
);
552 str
->buf
= (char *)new;
553 str
->bufsize
= newlen
;
557 str
->buf
= reallocf(str
->buf
, newlen
);
558 if (str
->buf
== NULL
)
565 str
->bufsize
= newlen
;
572 asl_string_append_char_no_encoding(asl_string_t
*str
, const char c
)
576 if (str
== NULL
) return NULL
;
579 if (str
->bufsize
== 0) len
++;
581 if (_asl_string_grow(str
, len
) < 0) return str
;
583 str
->buf
[str
->cursor
] = c
;
585 str
->buf
[str
->cursor
] = '\0';
587 if (str
->encoding
& ASL_STRING_LEN
)
590 snprintf(tmp
, sizeof(tmp
), "%10lu", str
->cursor
- 10);
591 memcpy(str
->buf
, tmp
, 10);
598 asl_string_append_no_encoding(asl_string_t
*str
, const char *app
)
602 if (str
== NULL
) return NULL
;
603 if (app
== NULL
) return str
;
605 applen
= strlen(app
);
607 if (str
->bufsize
== 0) len
++;
609 if (_asl_string_grow(str
, len
) < 0) return str
;
611 memcpy(str
->buf
+ str
->cursor
, app
, applen
);
613 str
->cursor
+= applen
;
614 str
->buf
[str
->cursor
] = '\0';
616 if (str
->encoding
& ASL_STRING_LEN
)
619 snprintf(tmp
, sizeof(tmp
), "%10lu", str
->cursor
- 10);
620 memcpy(str
->buf
, tmp
, 10);
626 static asl_string_t
*
627 asl_string_append_internal(asl_string_t
*str
, const char *app
, int encode_space
)
632 if (str
== NULL
) return NULL
;
633 if (app
== NULL
) return str
;
635 switch (str
->encoding
& ASL_ENCODE_MASK
)
637 case ASL_ENCODE_NONE
:
639 return asl_string_append_no_encoding(str
, app
);
641 case ASL_ENCODE_SAFE
:
643 /* minor encoding to reduce the likelyhood of spoof attacks */
646 for (p
= app
; *p
!= '\0'; p
++)
648 if ((*p
== 10) || (*p
== 13))
650 asl_string_append_no_encoding(str
, "\n\t");
654 asl_string_append_no_encoding(str
, "^H");
658 asl_string_append_char_no_encoding(str
, *p
);
666 for (p
= app
; *p
!= '\0'; p
++)
672 /* Meta chars get \M prefix */
675 /* except meta-space, which is \240 */
678 asl_string_append_no_encoding(str
, "\\240");
682 asl_string_append_no_encoding(str
, "\\M");
687 /* space is either ' ' or \s */
690 if (encode_space
== 0)
692 asl_string_append_char_no_encoding(str
, ' ');
696 asl_string_append_no_encoding(str
, "\\s");
701 if ((meta
== 0) && (x
== 92))
703 asl_string_append_no_encoding(str
, "\\\\");
707 /* [ and ] are escaped in ASL encoding */
708 if ((str
->encoding
& ASL_ENCODE_ASL
) && (meta
== 0) && ((*p
== 91) || (*p
== 93)))
710 if (*p
== '[') asl_string_append_no_encoding(str
, "\\[");
711 else asl_string_append_no_encoding(str
, "\\]");
720 asl_string_append_char_no_encoding(str
, '\\');
723 asl_string_append_no_encoding(str
, "^?");
727 /* 33-126 are printable (add a '-' prefix for meta) */
728 if ((x
>= 33) && (x
<= 126))
732 asl_string_append_char_no_encoding(str
, '-');
735 asl_string_append_char_no_encoding(str
, x
);
739 /* non-meta BEL, BS, HT, NL, VT, NP, CR (7-13) are \a, \b, \t, \n, \v, \f, and \r */
740 if ((meta
== 0) && (x
>= 7) && (x
<= 13))
742 asl_string_append_char_no_encoding(str
, '\\');
743 asl_string_append_char_no_encoding(str
, cvis_7_13
[x
- 7]);
747 /* 0 - 31 are ^@ - ^_ (non-meta get a leading \) */
752 asl_string_append_char_no_encoding(str
, '\\');
755 asl_string_append_char_no_encoding(str
, '^');
756 asl_string_append_char_no_encoding(str
, 64 + x
);
760 asl_string_append_char_no_encoding(str
, x
);
767 for (p
= app
; *p
!= '\0'; p
++)
773 asl_string_append_no_encoding(str
, "&");
777 asl_string_append_no_encoding(str
, "<");
781 asl_string_append_no_encoding(str
, ">");
785 asl_string_append_no_encoding(str
, """);
789 asl_string_append_no_encoding(str
, "'");
794 snprintf(tmp
, sizeof(tmp
), "&#x%02hhx;", x
);
795 asl_string_append_no_encoding(str
, tmp
);
799 asl_string_append_char_no_encoding(str
, x
);
813 asl_string_append(asl_string_t
*str
, const char *app
)
815 return asl_string_append_internal(str
, app
, 0);
819 asl_string_append_asl_key(asl_string_t
*str
, const char *app
)
821 return asl_string_append_internal(str
, app
, 1);
825 asl_string_append_op(asl_string_t
*str
, uint32_t op
)
830 if (str
== NULL
) return NULL
;
832 if (op
== ASL_QUERY_OP_NULL
)
834 return asl_string_append_char_no_encoding(str
, '.');
838 if (op
& ASL_QUERY_OP_CASEFOLD
) opstr
[i
++] = 'C';
840 if (op
& ASL_QUERY_OP_REGEX
) opstr
[i
++] = 'R';
842 if (op
& ASL_QUERY_OP_NUMERIC
) opstr
[i
++] = 'N';
844 if (op
& ASL_QUERY_OP_PREFIX
)
846 if (op
& ASL_QUERY_OP_SUFFIX
) opstr
[i
++] = 'S';
847 else opstr
[i
++] = 'A';
849 if (op
& ASL_QUERY_OP_SUFFIX
) opstr
[i
++] = 'Z';
851 switch (op
& ASL_QUERY_OP_TRUE
)
853 case ASL_QUERY_OP_EQUAL
:
856 case ASL_QUERY_OP_GREATER
:
859 case ASL_QUERY_OP_GREATER_EQUAL
:
863 case ASL_QUERY_OP_LESS
:
866 case ASL_QUERY_OP_LESS_EQUAL
:
870 case ASL_QUERY_OP_NOT_EQUAL
:
873 case ASL_QUERY_OP_TRUE
:
882 return asl_string_append_char_no_encoding(str
, '.');
886 return asl_string_append_no_encoding(str
, opstr
);
890 asl_string_append_xml_tag(asl_string_t
*str
, const char *tag
, const char *s
)
892 asl_string_append_no_encoding(str
, "\t\t<");
893 asl_string_append_no_encoding(str
, tag
);
894 asl_string_append_no_encoding(str
, ">");
895 asl_string_append_internal(str
, s
, 0);
896 asl_string_append_no_encoding(str
, "</");
897 asl_string_append_no_encoding(str
, tag
);
898 asl_string_append_no_encoding(str
, ">\n");