1/*
2 * Copyright (c) 2013 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#include <sys/errno.h>
30#include <sys/types.h>
31#include <sys/malloc.h>
32#include <sys/buf.h>
33#include <sys/time.h>
34#include <sys/kauth.h>
35#include <sys/mount.h>
36#include <sys/vnode.h>
37#include <sys/syslog.h>
38#include <sys/vnode_internal.h>
39#include <sys/fslog.h>
40#include <sys/mount_internal.h>
41#include <sys/kasl.h>
42
43#include <dev/random/randomdev.h>
44
45#include <uuid/uuid.h>
46
47#include <stdarg.h>
48
49/* String to append as format modifier for each key-value pair */
50#define KASL_KEYVAL_FMT "[%s %s] "
51#define KASL_KEYVAL_FMT_LEN (sizeof(KASL_KEYVAL_FMT) - 1)
52
53#define KASL_NEWLINE_CHAR "\n"
54#define KASL_NEWLINE_CHAR_LEN (sizeof(KASL_NEWLINE_CHAR) - 1)
55
56/* Length of entire ASL message in 10 characters. Kernel defaults to zero */
57#define KASL_ASL_MSG_LEN " 0"
58
59/* Length of default format string to be used by printf */
60#define MAX_FMT_LEN 256
61
62
63/* Function to print input values as key-value pairs in format
64 * identifiable by Apple system log (ASL) facility. All key-value pairs
65 * are assumed to be pointer to strings and are provided using two ways -
66 * (a) va_list argument which is a list of varying number of arguments
67 * created by the caller of this function.
68 * (b) variable number of arguments passed to this function.
69 *
70 * Parameters -
71 * level - Priority level for this ASL message
72 * facility - Facility for this ASL message.
73 * num_pairs - Number of key-value pairs provided by vargs argument.
74 * vargs - List of key-value pairs.
75 * ... - Additional key-value pairs (apart from vargs) as variable
76 * argument list. A NULL value indicates the end of the
77 * variable argument list.
78 *
79 * Returns -
80 * zero - On success, when it prints all key-values pairs provided.
81 * E2BIG - When it cannot print all key-value pairs provided and had
82 * to truncate the output.
83 */
84int
85kern_asl_msg_va(int level, const char *facility, int num_pairs, va_list vargs, ...)
86{
87 int err = 0;
88 char fmt[MAX_FMT_LEN]; /* Format string to use with vaddlog */
89 int calc_pairs = 0;
90 size_t len;
91 int i;
92 va_list ap;
93 char *ptr;
94
95 /* Mask extra bits, if any, from priority level */
96 level = LOG_PRI(level);
97
98 /* Create the first part of format string consisting of ASL
99 * message length, level, and facility.
100 */
101 if (facility) {
102 snprintf(fmt, MAX_FMT_LEN, "%s [%s %d] [%s %s] ",
103 KASL_ASL_MSG_LEN,
104 KASL_KEY_LEVEL, level,
105 KASL_KEY_FACILITY, facility);
106 } else {
107 snprintf(fmt, MAX_FMT_LEN, "%s [%s %d] ",
108 KASL_ASL_MSG_LEN,
109 KASL_KEY_LEVEL, level);
110 }
111
112 /* Determine the number of key-value format string [%s %s] that
113 * should be added in format string for every key-value pair provided
114 * in va_list. Calculate maximum number of format string that can be
115 * accommodated in the remaining format buffer (after saving space
116 * for newline character). If the caller provided pairs in va_list
117 * is more than calculated pairs, truncate extra pairs.
118 */
119 len = MAX_FMT_LEN - strlen(fmt) - KASL_NEWLINE_CHAR_LEN - 1;
120 calc_pairs = len / KASL_KEYVAL_FMT_LEN;
121 if (num_pairs <= calc_pairs) {
122 calc_pairs = num_pairs;
123 } else {
124 err = E2BIG;
125 }
126
127 /* Append format strings [%s %s] for the key-value pairs in vargs */
128 len = MAX_FMT_LEN - KASL_NEWLINE_CHAR_LEN;
129 for (i = 0; i < calc_pairs; i++) {
130 (void) strlcat(fmt, KASL_KEYVAL_FMT, len);
131 }
132
133 /* Count number of variable arguments provided to this function
134 * and determine total number of key-value pairs.
135 */
136 calc_pairs = 0;
137 va_start(ap, vargs);
138 ptr = va_arg(ap, char *);
139 while (ptr) {
140 calc_pairs++;
141 ptr = va_arg(ap, char *);
142 }
143 calc_pairs /= 2;
144 va_end(ap);
145
146 /* If user provided variable number of arguments, append them as
147 * as real key-value "[k v]" into the format string. If the format
148 * string is too small, ignore the key-value pair completely.
149 */
150 if (calc_pairs) {
151 char *key, *val;
152 size_t pairlen;
153 int offset;
154
155 /* Calculate bytes available for key-value pairs after reserving
156 * bytes for newline character and NULL terminator
157 */
158 len = MAX_FMT_LEN - strlen(fmt) - KASL_NEWLINE_CHAR_LEN - 1;
159 offset = strlen(fmt);
160
161 va_start(ap, vargs);
162 for (i = 0; i < calc_pairs; i++) {
163 key = va_arg(ap, char *);
164 val = va_arg(ap, char *);
165
166 /* Calculate bytes required to store next key-value pair
167 * as "[key val] " including space for '[', ']', and
168 * two spaces.
169 */
170 pairlen = strlen(key) + strlen(val) + 4;
171 if (pairlen > len) {
172 err = E2BIG;
173 break;
174 }
175
176 /* len + 1 because one byte has been set aside for NULL
177 * terminator in calculation of 'len' above
178 */
179 snprintf((fmt + offset), len + 1, KASL_KEYVAL_FMT,
180 key, val);
181 offset += pairlen;
182 len -= pairlen;
183 }
184 va_end(ap);
185 }
186
187 /* Append newline */
188 (void) strlcat(fmt, KASL_NEWLINE_CHAR, MAX_FMT_LEN);
189
190 /* Print the key-value pairs in ASL format */
191 vaddlog(fmt, vargs);
192
193 /*
194 * Note: can't use os_log_with_args() here because 'fmt' is
195 * constructed on the stack i.e. doesn't come from a text
196 * section. More importantly, the newer logging system
197 * doesn't grok ASL either.
198 */
199
200 return (err);
201}
202
203int
204kern_asl_msg(int level, const char *facility, int num_pairs, ...)
205{
206 int err;
207 va_list ap;
208
209 va_start(ap, num_pairs);
210 err = kern_asl_msg_va(level, facility,
211 num_pairs, ap, NULL);
212 va_end(ap);
213
214 return err;
215}
216
217/* Search if given string contains '[' and ']'. If any, escape it by
218 * prefixing with a '\'. If the length of the string is not big enough,
219 * no changes are done and error is returned.
220 *
221 * Parameters -
222 * str - string that can contain '[' or ']', should be NULL terminated
223 * len - length, in bytes, of valid data, including NULL character.
224 * buflen - size of buffer that contains the string
225 */
226int
227escape_str(char *str, int len, int buflen)
228{
229 int count;
230 char *src, *dst;
231
232 /* Count number of characters to escape */
233 src = str;
234 count = 0;
235 do {
236 if ((*src == '[') || (*src == ']')) {
237 count++;
238 }
239 } while (*src++);
240
241 if (count) {
242 /*
243 * Check if the buffer has enough space to escape all
244 * characters
245 */
246 if ((buflen - len) < count) {
247 return (ENOSPC);
248 }
249
250 src = str + len;
251 dst = src + count;
252 while (count) {
253 *dst-- = *src;
254 if ((*src == '[') || (*src == ']')) {
255 /* Last char copied needs to be escaped */
256 *dst-- = '\\';
257 count--;
258 }
259 src--;
260 }
261 }
262
263 return (0);
264}
265