1/* 2 * Copyright (c) 1999-2002, 2011 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/* 25 * cfutil.c 26 * - CF utility functions 27 */ 28 29/* 30 * Modification History 31 * 32 * February 15, 2002 Dieter Siegmund (dieter@apple.com) 33 * - broken out of ipconfigd.c 34 */ 35 36#include <stdlib.h> 37#include <unistd.h> 38#include <stdio.h> 39#include <sys/stat.h> 40#include <fcntl.h> 41#include <ctype.h> 42#include <string.h> 43#include <sys/param.h> 44#include <arpa/inet.h> 45#include <net/ethernet.h> 46#include <SystemConfiguration/SCValidation.h> 47#include <CoreFoundation/CFData.h> 48#include "util.h" 49#include "cfutil.h" 50 51#include "symbol_scope.h" 52 53PRIVATE_EXTERN void 54my_CFRelease(void * t) 55{ 56 void * * obj = (void * *)t; 57 if (obj && *obj) { 58 CFRelease(*obj); 59 *obj = NULL; 60 } 61 return; 62} 63 64static void * 65read_file(const char * filename, size_t * data_length) 66{ 67 void * data = NULL; 68 size_t len = 0; 69 int fd = -1; 70 struct stat sb; 71 72 *data_length = 0; 73 if (stat(filename, &sb) < 0) 74 goto done; 75 len = sb.st_size; 76 if (len == 0) 77 goto done; 78 79 data = malloc(len); 80 if (data == NULL) 81 goto done; 82 83 fd = open(filename, O_RDONLY); 84 if (fd < 0) 85 goto done; 86 87 if (read(fd, data, len) != len) { 88 goto done; 89 } 90 done: 91 if (fd >= 0) 92 close(fd); 93 if (data) { 94 *data_length = len; 95 } 96 return (data); 97} 98 99static int 100write_file(const char * filename, const void * data, size_t data_length, 101 mode_t permissions) 102{ 103 char path[MAXPATHLEN]; 104 int fd = -1; 105 int ret = 0; 106 107 snprintf(path, sizeof(path), "%s-", filename); 108 fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, permissions); 109 if (fd < 0) { 110 ret = -1; 111 goto done; 112 } 113 114 if (write(fd, data, data_length) != data_length) { 115 ret = -1; 116 goto done; 117 } 118 rename(path, filename); 119 done: 120 if (fd >= 0) { 121 close(fd); 122 } 123 return (ret); 124} 125 126PRIVATE_EXTERN CFPropertyListRef 127my_CFPropertyListCreateFromFile(const char * filename) 128{ 129 void * buf; 130 size_t bufsize; 131 CFDataRef data = NULL; 132 CFPropertyListRef plist = NULL; 133 134 buf = read_file(filename, &bufsize); 135 if (buf == NULL) { 136 return (NULL); 137 } 138 data = CFDataCreateWithBytesNoCopy(NULL, buf, bufsize, kCFAllocatorNull); 139 if (data == NULL) { 140 goto done; 141 } 142 plist = CFPropertyListCreateWithData(NULL, 143 data, 144 kCFPropertyListImmutable, 145 NULL, 146 NULL); 147 done: 148 if (data) 149 CFRelease(data); 150 if (buf) 151 free(buf); 152 return (plist); 153} 154 155PRIVATE_EXTERN int 156my_CFPropertyListWriteFile(CFPropertyListRef plist, const char * filename, 157 mode_t permissions) 158{ 159 CFDataRef data; 160 int ret; 161 162 if (plist == NULL) 163 return (0); 164 165 data = CFPropertyListCreateData(NULL, 166 plist, 167 kCFPropertyListXMLFormat_v1_0, 168 0, 169 NULL); 170 if (data == NULL) { 171 return (0); 172 } 173 ret = write_file(filename, 174 (const void *)CFDataGetBytePtr(data), 175 CFDataGetLength(data), 176 permissions); 177 CFRelease(data); 178 return (ret); 179} 180 181PRIVATE_EXTERN int 182my_CFStringToCStringAndLengthExt(CFStringRef cfstr, char * str, int len, 183 boolean_t is_external) 184{ 185 CFIndex ret_len = 0; 186 187 CFStringGetBytes(cfstr, CFRangeMake(0, CFStringGetLength(cfstr)), 188 kCFStringEncodingUTF8, 0, is_external, 189 (UInt8 *)str, len - 1, &ret_len); 190 if (str != NULL) { 191 str[ret_len] = '\0'; 192 } 193 return ((int)ret_len + 1); /* leave 1 byte for nul-termination */ 194} 195 196PRIVATE_EXTERN Boolean 197my_CFStringArrayToCStringArray(CFArrayRef arr, void * buffer, int * buffer_size, 198 int * ret_count) 199{ 200 CFIndex count = CFArrayGetCount(arr); 201 int i; 202 char * offset = NULL; 203 int space; 204 char * * strlist = NULL; 205 206 space = (int)count * sizeof(char *); 207 if (buffer != NULL) { 208 if (*buffer_size < space) { 209 /* not enough space for even the pointer list */ 210 return (FALSE); 211 } 212 strlist = (char * *)buffer; 213 offset = buffer + space; /* the start of the 1st string */ 214 } 215 for (i = 0; i < count; i++) { 216 int len = 0; 217 CFStringRef str; 218 219 str = CFArrayGetValueAtIndex(arr, i); 220 if (isA_CFString(str) == NULL) { 221 return (FALSE); 222 } 223 if (buffer != NULL) { 224 len = *buffer_size - space; 225 if (len < 0) { 226 return (FALSE); 227 } 228 } 229 len = my_CFStringToCStringAndLength(str, offset, len); 230 if (buffer != NULL) { 231 strlist[i] = offset; 232 offset += len; 233 } 234 space += len; 235 } 236 *buffer_size = roundup(space, sizeof(char *)); 237 *ret_count = (int)count; 238 return (TRUE); 239} 240 241PRIVATE_EXTERN Boolean 242my_CFStringArrayToEtherArray(CFArrayRef array, char * buffer, int * buffer_size, 243 int * ret_count) 244{ 245 CFIndex count = CFArrayGetCount(array); 246 int i; 247 struct ether_addr * list = NULL; 248 int space; 249 250 space = roundup((int)count * sizeof(*list), sizeof(char *)); 251 if (buffer != NULL) { 252 if (*buffer_size < space) { 253 /* not enough space for all elements */ 254 return (FALSE); 255 } 256 list = (struct ether_addr *)buffer; 257 } 258 for (i = 0; i < count; i++) { 259 struct ether_addr * eaddr; 260 CFStringRef str = CFArrayGetValueAtIndex(array, i); 261 char val[64]; 262 263 if (isA_CFString(str) == NULL) { 264 return (FALSE); 265 } 266 if (CFStringGetCString(str, val, sizeof(val), kCFStringEncodingASCII) 267 == FALSE) { 268 return (FALSE); 269 } 270 eaddr = ether_aton((char *)val); 271 if (eaddr == NULL) { 272 return (FALSE); 273 } 274 if (list != NULL) { 275 list[i] = *eaddr; 276 } 277 } 278 *buffer_size = space; 279 *ret_count = (int)count; 280 return (TRUE); 281} 282 283PRIVATE_EXTERN bool 284my_CFStringToIPAddress(CFStringRef str, struct in_addr * ret_ip) 285{ 286 char buf[64]; 287 288 ret_ip->s_addr = 0; 289 if (isA_CFString(str) == NULL) { 290 return (FALSE); 291 } 292 if (CFStringGetCString(str, buf, sizeof(buf), kCFStringEncodingASCII) 293 == FALSE) { 294 return (FALSE); 295 } 296 if (inet_aton(buf, ret_ip) == 1) { 297 return (TRUE); 298 } 299 return (FALSE); 300} 301 302PRIVATE_EXTERN bool 303my_CFStringToNumber(CFStringRef str, uint32_t * ret_val) 304{ 305 char buf[64]; 306 unsigned long val; 307 308 my_CFStringToCStringAndLength(str, buf, sizeof(buf)); 309 val = strtoul(buf, NULL, 0); 310 if (val != ULONG_MAX && errno != ERANGE) { 311 *ret_val = (uint32_t)val; 312 return (TRUE); 313 } 314 return (FALSE); 315} 316 317PRIVATE_EXTERN bool 318my_CFTypeToNumber(CFTypeRef element, uint32_t * l_p) 319{ 320 if (isA_CFString(element) != NULL) { 321 if (my_CFStringToNumber(element, l_p) == FALSE) { 322 return (FALSE); 323 } 324 } 325 else if (isA_CFBoolean(element) != NULL) { 326 *l_p = CFBooleanGetValue(element); 327 } 328 else if (isA_CFNumber(element) != NULL) { 329 if (CFNumberGetValue(element, kCFNumberSInt32Type, l_p) 330 == FALSE) { 331 return (FALSE); 332 } 333 } 334 else { 335 return (FALSE); 336 } 337 return (TRUE); 338} 339 340PRIVATE_EXTERN void 341my_CFDictionarySetTypeAsArrayValue(CFMutableDictionaryRef dict, 342 CFStringRef prop, CFTypeRef val) 343{ 344 CFArrayRef array; 345 346 array = CFArrayCreate(NULL, (const void **)&val, 1, 347 &kCFTypeArrayCallBacks); 348 if (array != NULL) { 349 CFDictionarySetValue(dict, prop, array); 350 CFRelease(array); 351 } 352 return; 353} 354 355PRIVATE_EXTERN void 356my_CFDictionarySetIPAddressAsArrayValue(CFMutableDictionaryRef dict, 357 CFStringRef prop, 358 struct in_addr ip_addr) 359{ 360 CFStringRef str; 361 362 str = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), 363 IP_LIST(&ip_addr)); 364 my_CFDictionarySetTypeAsArrayValue(dict, prop, str); 365 CFRelease(str); 366 return; 367} 368 369PRIVATE_EXTERN void 370my_CFArrayAppendUniqueValue(CFMutableArrayRef arr, CFTypeRef new) 371{ 372 CFIndex count; 373 int i; 374 375 count = CFArrayGetCount(arr); 376 for (i = 0; i < count; i++) { 377 CFStringRef element = CFArrayGetValueAtIndex(arr, i); 378 if (CFEqual(element, new)) { 379 return; 380 } 381 } 382 CFArrayAppendValue(arr, new); 383 return; 384} 385 386PRIVATE_EXTERN Boolean 387my_CFEqual(CFTypeRef val1, CFTypeRef val2) 388{ 389 if (val1 == NULL) { 390 if (val2 == NULL) { 391 return (TRUE); 392 } 393 return (FALSE); 394 } 395 if (val2 == NULL) { 396 return (FALSE); 397 } 398 if (CFGetTypeID(val1) != CFGetTypeID(val2)) { 399 return (FALSE); 400 } 401 return (CFEqual(val1, val2)); 402} 403 404 405/* 406 * Function: my_CFStringCopyComponent 407 * Purpose: 408 * Separates the given string using the given separator, and returns 409 * the component at the specified index. 410 * Returns: 411 * NULL if no such component exists, non-NULL component otherwise 412 */ 413PRIVATE_EXTERN CFStringRef 414my_CFStringCopyComponent(CFStringRef path, CFStringRef separator, 415 CFIndex component_index) 416{ 417 CFArrayRef arr; 418 CFStringRef component = NULL; 419 420 arr = CFStringCreateArrayBySeparatingStrings(NULL, path, separator); 421 if (arr == NULL) { 422 goto done; 423 } 424 if (CFArrayGetCount(arr) <= component_index) { 425 goto done; 426 } 427 component = CFRetain(CFArrayGetValueAtIndex(arr, component_index)); 428 429 done: 430 my_CFRelease(&arr); 431 return (component); 432 433} 434 435CFStringRef 436my_CFStringCreateWithIPAddress(const struct in_addr ip) 437{ 438 return (CFStringCreateWithFormat(NULL, NULL, 439 CFSTR(IP_FORMAT), IP_LIST(&ip))); 440} 441 442CFStringRef 443my_CFStringCreateWithIPv6Address(const void * ip6_addr) 444{ 445 char ntopbuf[INET6_ADDRSTRLEN]; 446 const char * c_str; 447 448 c_str = inet_ntop(AF_INET6, ip6_addr, ntopbuf, sizeof(ntopbuf)); 449 return (CFStringCreateWithCString(NULL, c_str, kCFStringEncodingASCII)); 450} 451 452void 453my_CFStringAppendBytesAsHex(CFMutableStringRef str, const uint8_t * bytes, 454 int length, char separator) 455{ 456 int i; 457 458 for (i = 0; i < length; i++) { 459 char sep[3]; 460 461 if (i == 0) { 462 sep[0] = '\0'; 463 } 464 else { 465 if ((i % 8) == 0 && separator == ' ') { 466 sep[0] = sep[1] = ' '; 467 sep[2] = '\0'; 468 } 469 else { 470 sep[0] = separator; 471 sep[1] = '\0'; 472 } 473 } 474 CFStringAppendFormat(str, NULL, CFSTR("%s%02x"), sep, bytes[i]); 475 } 476 return; 477} 478 479char * 480my_CFStringToCString(CFStringRef cfstr, CFStringEncoding encoding) 481{ 482 CFIndex l; 483 CFRange range; 484 uint8_t * str; 485 486 range = CFRangeMake(0, CFStringGetLength(cfstr)); 487 CFStringGetBytes(cfstr, range, encoding, 488 0, FALSE, NULL, 0, &l); 489 if (l <= 0) { 490 return (NULL); 491 } 492 str = (uint8_t *)malloc(l + 1); 493 CFStringGetBytes(cfstr, range, encoding, 0, FALSE, str, l, &l); 494 str[l] = '\0'; 495 return ((char *)str); 496} 497 498