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 return (err); 194} 195 196int 197kern_asl_msg(int level, const char *facility, int num_pairs, ...) 198{ 199 int err; 200 va_list ap; 201 202 va_start(ap, num_pairs); 203 err = kern_asl_msg_va(level, facility, 204 num_pairs, ap, NULL); 205 va_end(ap); 206 207 return err; 208} 209 210/* Search if given string contains '[' and ']'. If any, escape it by 211 * prefixing with a '\'. If the length of the string is not big enough, 212 * no changes are done and error is returned. 213 * 214 * Parameters - 215 * str - string that can contain '[' or ']', should be NULL terminated 216 * len - length, in bytes, of valid data, including NULL character. 217 * buflen - size of buffer that contains the string 218 */ 219int 220escape_str(char *str, int len, int buflen) 221{ 222 int count; 223 char *src, *dst; 224 225 /* Count number of characters to escape */ 226 src = str; 227 count = 0; 228 do { 229 if ((*src == '[') || (*src == ']')) { 230 count++; 231 } 232 } while (*src++); 233 234 if (count) { 235 /* 236 * Check if the buffer has enough space to escape all 237 * characters 238 */ 239 if ((buflen - len) < count) { 240 return (ENOSPC); 241 } 242 243 src = str + len; 244 dst = src + count; 245 while (count) { 246 *dst-- = *src; 247 if ((*src == '[') || (*src == ']')) { 248 /* Last char copied needs to be escaped */ 249 *dst-- = '\\'; 250 count--; 251 } 252 src--; 253 } 254 } 255 256 return (0); 257} 258