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 #define ASL_STRING_QUANTUM 256
34 static const char *cvis_7_13
= "abtnvfr";
37 * Message ID generation
39 static uint64_t _asl_core_msg_next_id
= 1;
40 static pthread_mutex_t core_lock
= PTHREAD_MUTEX_INITIALIZER
;
42 #define mix(a, b, c) \
44 a -= b; a -= c; a ^= (c>>13); \
45 b -= c; b -= a; b ^= (a<< 8); \
46 c -= a; c -= b; c ^= (b>>13); \
47 a -= b; a -= c; a ^= (c>>12); \
48 b -= c; b -= a; b ^= (a<<16); \
49 c -= a; c -= b; c ^= (b>> 5); \
50 a -= b; a -= c; a ^= (c>> 3); \
51 b -= c; b -= a; b ^= (a<<10); \
52 c -= a; c -= b; c ^= (b>>15); \
56 * Hash is used to improve string search.
59 asl_core_string_hash(const char *s
, uint32_t inlen
)
61 uint32_t a
, b
, c
, l
, len
;
63 if (s
== NULL
) return 0;
68 if (s
[0] == '\0') return 0;
78 a
+= (s
[0] + ((uint32_t)s
[1]<<8) + ((uint32_t)s
[ 2]<<16) + ((uint32_t)s
[ 3]<<24));
79 b
+= (s
[4] + ((uint32_t)s
[5]<<8) + ((uint32_t)s
[ 6]<<16) + ((uint32_t)s
[ 7]<<24));
80 c
+= (s
[8] + ((uint32_t)s
[9]<<8) + ((uint32_t)s
[10]<<16) + ((uint32_t)s
[11]<<24));
91 case 11: c
+= ((uint32_t)s
[10]<<24);
92 case 10: c
+= ((uint32_t)s
[9]<<16);
93 case 9 : c
+= ((uint32_t)s
[8]<<8);
95 case 8 : b
+= ((uint32_t)s
[7]<<24);
96 case 7 : b
+= ((uint32_t)s
[6]<<16);
97 case 6 : b
+= ((uint32_t)s
[5]<<8);
100 case 4 : a
+= ((uint32_t)s
[3]<<24);
101 case 3 : a
+= ((uint32_t)s
[2]<<16);
102 case 2 : a
+= ((uint32_t)s
[1]<<8);
113 asl_core_error(uint32_t code
)
117 case ASL_STATUS_OK
: return "Operation Succeeded";
118 case ASL_STATUS_INVALID_ARG
: return "Invalid Argument";
119 case ASL_STATUS_INVALID_STORE
: return "Invalid Data Store";
120 case ASL_STATUS_INVALID_STRING
: return "Invalid String";
121 case ASL_STATUS_INVALID_ID
: return "Invalid ID Number";
122 case ASL_STATUS_INVALID_MESSAGE
: return "Invalid Message";
123 case ASL_STATUS_NOT_FOUND
: return "Not Found";
124 case ASL_STATUS_READ_FAILED
: return "Read Operation Failed";
125 case ASL_STATUS_WRITE_FAILED
: return "Write Operation Failed";
126 case ASL_STATUS_NO_MEMORY
: return "System Memory Allocation Failed";
127 case ASL_STATUS_ACCESS_DENIED
: return "Access Denied";
128 case ASL_STATUS_READ_ONLY
: return "Read Only Access";
129 case ASL_STATUS_WRITE_ONLY
: return "Write Only Access";
130 case ASL_STATUS_MATCH_FAILED
: return "Match Failed";
131 case ASL_STATUS_NO_RECORDS
: return "No More Records";
134 return "Operation Failed";
138 asl_core_check_user_access(int32_t msgu
, int32_t readu
)
140 /* -1 means anyone may read */
141 if (msgu
== -1) return ASL_STATUS_OK
;
143 /* Check for exact match */
144 if (msgu
== readu
) return ASL_STATUS_OK
;
146 return ASL_STATUS_ACCESS_DENIED
;
150 asl_core_check_group_access(int32_t msgg
, int32_t readu
, int32_t readg
)
155 /* -1 means anyone may read */
156 if (msgg
== -1) return ASL_STATUS_OK
;
158 /* Check for exact match */
159 if (msgg
== readg
) return ASL_STATUS_OK
;
161 /* Check if user (u) is in read group (msgg) */
162 mbr_uid_to_uuid(readu
, uu
);
163 mbr_gid_to_uuid(msgg
, gu
);
166 mbr_check_membership(uu
, gu
, &check
);
167 if (check
!= 0) return ASL_STATUS_OK
;
169 return ASL_STATUS_ACCESS_DENIED
;
173 asl_core_check_access(int32_t msgu
, int32_t msgg
, int32_t readu
, int32_t readg
, uint16_t flags
)
177 /* root (uid 0) may always read */
178 if (readu
== 0) return ASL_STATUS_OK
;
180 uset
= flags
& ASL_MSG_FLAG_READ_UID_SET
;
181 gset
= flags
& ASL_MSG_FLAG_READ_GID_SET
;
183 /* if no access controls are set, anyone may read */
184 if ((uset
| gset
) == 0) return ASL_STATUS_OK
;
186 /* if only uid is set, then access is only by uid match */
187 if ((uset
!= 0) && (gset
== 0)) return asl_core_check_user_access(msgu
, readu
);
189 /* if only gid is set, then access is only by gid match */
190 if ((uset
== 0) && (gset
!= 0)) return asl_core_check_group_access(msgg
, readu
, readg
);
192 /* both uid and gid are set - check user, then group */
193 if ((asl_core_check_user_access(msgu
, readu
)) == ASL_STATUS_OK
) return ASL_STATUS_OK
;
194 return asl_core_check_group_access(msgg
, readu
, readg
);
198 asl_core_htonq(uint64_t n
)
200 #ifdef __BIG_ENDIAN__
212 x
.l
[0] = htonl(x
.l
[1]);
220 asl_core_ntohq(uint64_t n
)
222 #ifdef __BIG_ENDIAN__
234 x
.l
[0] = ntohl(x
.l
[1]);
242 asl_core_new_msg_id(uint64_t start
)
246 pthread_mutex_lock(&core_lock
);
248 if (start
!= 0) _asl_core_msg_next_id
= start
;
250 out
= _asl_core_msg_next_id
;
251 _asl_core_msg_next_id
++;
253 pthread_mutex_unlock(&core_lock
);
259 * asl_core_encode_buffer
260 * encode arbitrary data as a C string without embedded zero (nul) characters
262 * The routine computes a histogram of the input buffer and finds
263 * the two least frequently used non-nul chars (L[0] and L[1]).
265 * L[0] is used to stand in for nul.
266 * L[1] is used as the escape character.
267 * Occurrences of nul in the data are encoded as L[0]
268 * Occurrences of L[0] in the data are encoded as the sequence L[1] 1.
269 * Occurrences of L[1] in the data are encoded as the sequence L[1] 2.
271 * The output string is preceded by L[0] L[1], and is nul terminated.
272 * The output length is 2 + n + N(L[0]) + N(L[1]) + 1
273 * where N(x) is the number of occurrences of x in the input string.
274 * The worst case occurs when all characters are equally frequent,
275 * In that case the output size will less that 1% larger than the input.
278 asl_core_encode_buffer(const char *in
, uint32_t len
)
281 uint32_t i
, j
, k
, outlen
, breakit
, min
, hist
[256];
282 uint32_t lfu
[2], save
[2];
285 if (in
== NULL
) return NULL
;
286 if (len
== 0) return NULL
;
288 memset(hist
, 0, sizeof(hist
));
292 for (i
= 0; i
< len
; i
++)
298 for (j
= 0; j
< 2; j
++)
303 for (i
= 2; i
< 256; i
++)
311 * Stop if there are no occurances or character i in the input.
312 * The minimum will never be less than zero.
317 * When looking for the second least frequently used character,
318 * stop scanning if we hit the same minimum as we saw in the first
319 * pass. There will be no smaller values.
321 if ((j
== 1) && (min
== save
[0])) break;
325 save
[j
] = hist
[lfu
[j
]];
326 hist
[lfu
[j
]] = (uint32_t)-1;
329 outlen
= 2 + len
+ save
[0] + save
[1] + 1;
331 str
= malloc(outlen
);
332 if (str
== NULL
) return NULL
;
334 str
[outlen
- 1] = '\0';
341 for (i
= 0; i
< len
; i
++)
351 for (k
= 0; (k
< 2) && (breakit
== 0); k
++)
361 if (breakit
== 1) continue;
370 * asl_core_decode_buffer
371 * decode a string produced by asl_encode_buffer to recreate the original data
374 asl_core_decode_buffer(const char *in
, char **buf
, uint32_t *len
)
377 uint32_t i
, j
, n
, outlen
;
381 if (buf
== NULL
) return -1;
382 if (len
== NULL
) return -1;
389 /* strip trailing nul */
392 /* determine output length and check for invalid input */
393 for (i
= 2; i
< n
; i
++)
399 if (i
== n
) return -1;
402 if ((v
< 1) || (v
> 2)) return -1;
409 if (outlen
== 0) return -1;
411 out
= malloc(outlen
);
412 if (out
== NULL
) return -1;
415 for (i
= 2; i
< n
; i
++)
422 else if (v
== lfu
[1])
426 out
[j
++] = lfu
[v
- 1];
436 /* asl_string_t support */
439 asl_string_new(uint32_t encoding
)
441 asl_string_t
*str
= (asl_string_t
*)calloc(1, sizeof(asl_string_t
));
442 if (str
== NULL
) return NULL
;
444 str
->encoding
= encoding
;
445 str
->delta
= ASL_STRING_QUANTUM
;
446 if (encoding
& ASL_STRING_VM
) str
->delta
= PAGE_SIZE
;
450 if (encoding
& ASL_STRING_LEN
) asl_string_append_no_encoding(str
, " 0 ");
455 asl_string_free(asl_string_t
*str
)
457 if (str
== NULL
) return;
459 if (str
->encoding
& ASL_STRING_VM
)
461 vm_deallocate(mach_task_self(), (vm_address_t
)str
->buf
, str
->bufsize
);
472 asl_string_free_return_bytes(asl_string_t
*str
)
475 if (str
== NULL
) return NULL
;
483 asl_string_bytes(asl_string_t
*str
)
485 if (str
== NULL
) return NULL
;
489 /* length includes trailing nul */
491 asl_string_length(asl_string_t
*str
)
493 if (str
== NULL
) return 0;
494 if (str
->cursor
== 0) return 0;
496 return str
->cursor
+ 1;
500 asl_string_allocated_size(asl_string_t
*str
)
502 if (str
== NULL
) return 0;
507 _asl_string_grow(asl_string_t
*str
, size_t len
)
511 if (str
== NULL
) return -1;
512 if (len
== 0) return 0;
514 if (str
->bufsize
== 0)
516 newlen
= ((len
+ str
->delta
- 1) / str
->delta
) * str
->delta
;
520 /* used size is (str->cursor + 1) including tailiing nul */
521 if (len
<= (str
->bufsize
- (str
->cursor
+ 1))) return 0;
523 /* really this is ((str->cursor + 1) + len + (str->delta - 1)) */
524 newlen
= ((str
->cursor
+ len
+ str
->delta
) / str
->delta
) * str
->delta
;
527 if (str
->encoding
& ASL_STRING_VM
)
529 kern_return_t kstatus
;
530 vm_address_t
new = 0;
532 kstatus
= vm_allocate(mach_task_self(), &new, newlen
, TRUE
);
533 if (kstatus
!= KERN_SUCCESS
)
540 if (str
->buf
!= NULL
)
542 memcpy((void *)new, str
->buf
, str
->bufsize
);
543 vm_deallocate(mach_task_self(), (vm_address_t
)str
->buf
, str
->bufsize
);
546 str
->buf
= (char *)new;
547 str
->bufsize
= newlen
;
551 str
->buf
= reallocf(str
->buf
, newlen
);
552 if (str
->buf
== NULL
)
559 str
->bufsize
= newlen
;
566 asl_string_append_char_no_encoding(asl_string_t
*str
, const char c
)
570 if (str
== NULL
) return NULL
;
573 if (str
->bufsize
== 0) len
++;
575 if (_asl_string_grow(str
, len
) < 0) return str
;
577 str
->buf
[str
->cursor
] = c
;
579 str
->buf
[str
->cursor
] = '\0';
581 if (str
->encoding
& ASL_STRING_LEN
)
584 snprintf(tmp
, sizeof(tmp
), "%10lu", str
->cursor
- 10);
585 memcpy(str
->buf
, tmp
, 10);
592 asl_string_append_no_encoding(asl_string_t
*str
, const char *app
)
596 if (str
== NULL
) return NULL
;
597 if (app
== NULL
) return str
;
599 applen
= strlen(app
);
601 if (str
->bufsize
== 0) len
++;
603 if (_asl_string_grow(str
, len
) < 0) return str
;
605 memcpy(str
->buf
+ str
->cursor
, app
, applen
);
607 str
->cursor
+= applen
;
608 str
->buf
[str
->cursor
] = '\0';
610 if (str
->encoding
& ASL_STRING_LEN
)
613 snprintf(tmp
, sizeof(tmp
), "%10lu", str
->cursor
- 10);
614 memcpy(str
->buf
, tmp
, 10);
620 static asl_string_t
*
621 asl_string_append_internal(asl_string_t
*str
, const char *app
, int encode_space
)
626 if (str
== NULL
) return NULL
;
627 if (app
== NULL
) return str
;
629 switch (str
->encoding
& ASL_ENCODE_MASK
)
631 case ASL_ENCODE_NONE
:
633 return asl_string_append_no_encoding(str
, app
);
635 case ASL_ENCODE_SAFE
:
637 /* minor encoding to reduce the likelyhood of spoof attacks */
640 for (p
= app
; *p
!= '\0'; p
++)
642 if ((*p
== 10) || (*p
== 13))
644 asl_string_append_no_encoding(str
, "\n\t");
648 asl_string_append_no_encoding(str
, "^H");
652 asl_string_append_char_no_encoding(str
, *p
);
660 for (p
= app
; *p
!= '\0'; p
++)
666 /* Meta chars get \M prefix */
669 /* except meta-space, which is \240 */
672 asl_string_append_no_encoding(str
, "\\240");
676 asl_string_append_no_encoding(str
, "\\M");
681 /* space is either ' ' or \s */
684 if (encode_space
== 0)
686 asl_string_append_char_no_encoding(str
, ' ');
690 asl_string_append_no_encoding(str
, "\\s");
695 if ((meta
== 0) && (x
== 92))
697 asl_string_append_no_encoding(str
, "\\\\");
701 /* [ and ] are escaped in ASL encoding */
702 if ((str
->encoding
& ASL_ENCODE_ASL
) && (meta
== 0) && ((*p
== 91) || (*p
== 93)))
704 if (*p
== '[') asl_string_append_no_encoding(str
, "\\[");
705 else asl_string_append_no_encoding(str
, "\\]");
714 asl_string_append_char_no_encoding(str
, '\\');
717 asl_string_append_no_encoding(str
, "^?");
721 /* 33-126 are printable (add a '-' prefix for meta) */
722 if ((x
>= 33) && (x
<= 126))
726 asl_string_append_char_no_encoding(str
, '-');
729 asl_string_append_char_no_encoding(str
, x
);
733 /* non-meta BEL, BS, HT, NL, VT, NP, CR (7-13) are \a, \b, \t, \n, \v, \f, and \r */
734 if ((meta
== 0) && (x
>= 7) && (x
<= 13))
736 asl_string_append_char_no_encoding(str
, '\\');
737 asl_string_append_char_no_encoding(str
, cvis_7_13
[x
- 7]);
741 /* 0 - 31 are ^@ - ^_ (non-meta get a leading \) */
746 asl_string_append_char_no_encoding(str
, '\\');
749 asl_string_append_char_no_encoding(str
, '^');
750 asl_string_append_char_no_encoding(str
, 64 + x
);
754 asl_string_append_char_no_encoding(str
, x
);
761 for (p
= app
; *p
!= '\0'; p
++)
767 asl_string_append_no_encoding(str
, "&");
771 asl_string_append_no_encoding(str
, "<");
775 asl_string_append_no_encoding(str
, ">");
779 asl_string_append_no_encoding(str
, """);
783 asl_string_append_no_encoding(str
, "'");
788 snprintf(tmp
, sizeof(tmp
), "&#x%02hhx;", x
);
789 asl_string_append_no_encoding(str
, tmp
);
793 asl_string_append_char_no_encoding(str
, x
);
807 asl_string_append(asl_string_t
*str
, const char *app
)
809 return asl_string_append_internal(str
, app
, 0);
813 asl_string_append_asl_key(asl_string_t
*str
, const char *app
)
815 return asl_string_append_internal(str
, app
, 1);
819 asl_string_append_op(asl_string_t
*str
, uint32_t op
)
824 if (str
== NULL
) return NULL
;
826 if (op
== ASL_QUERY_OP_NULL
)
828 return asl_string_append_char_no_encoding(str
, '.');
832 if (op
& ASL_QUERY_OP_CASEFOLD
) opstr
[i
++] = 'C';
834 if (op
& ASL_QUERY_OP_REGEX
) opstr
[i
++] = 'R';
836 if (op
& ASL_QUERY_OP_NUMERIC
) opstr
[i
++] = 'N';
838 if (op
& ASL_QUERY_OP_PREFIX
)
840 if (op
& ASL_QUERY_OP_SUFFIX
) opstr
[i
++] = 'S';
841 else opstr
[i
++] = 'A';
843 if (op
& ASL_QUERY_OP_SUFFIX
) opstr
[i
++] = 'Z';
845 switch (op
& ASL_QUERY_OP_TRUE
)
847 case ASL_QUERY_OP_EQUAL
:
850 case ASL_QUERY_OP_GREATER
:
853 case ASL_QUERY_OP_GREATER_EQUAL
:
857 case ASL_QUERY_OP_LESS
:
860 case ASL_QUERY_OP_LESS_EQUAL
:
864 case ASL_QUERY_OP_NOT_EQUAL
:
867 case ASL_QUERY_OP_TRUE
:
876 return asl_string_append_char_no_encoding(str
, '.');
880 return asl_string_append_no_encoding(str
, opstr
);
884 asl_string_append_xml_tag(asl_string_t
*str
, const char *tag
, const char *s
)
886 asl_string_append_no_encoding(str
, "\t\t<");
887 asl_string_append_no_encoding(str
, tag
);
888 asl_string_append_no_encoding(str
, ">");
889 asl_string_append_no_encoding(str
, s
);
890 asl_string_append_no_encoding(str
, "</");
891 asl_string_append_no_encoding(str
, tag
);
892 asl_string_append_no_encoding(str
, ">\n");