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 = CFPropertyListCreateFromXMLData(NULL, data, 143 kCFPropertyListImmutable, 144 NULL); 145 done: 146 if (data) 147 CFRelease(data); 148 if (buf) 149 free(buf); 150 return (plist); 151} 152 153PRIVATE_EXTERN int 154my_CFPropertyListWriteFile(CFPropertyListRef plist, const char * filename, 155 mode_t permissions) 156{ 157 CFDataRef data; 158 int ret; 159 160 if (plist == NULL) 161 return (0); 162 163 data = CFPropertyListCreateXMLData(NULL, plist); 164 if (data == NULL) { 165 return (0); 166 } 167 ret = write_file(filename, 168 (const void *)CFDataGetBytePtr(data), 169 CFDataGetLength(data), 170 permissions); 171 CFRelease(data); 172 return (ret); 173} 174 175PRIVATE_EXTERN int 176my_CFStringToCStringAndLengthExt(CFStringRef cfstr, char * str, int len, 177 boolean_t is_external) 178{ 179 CFIndex ret_len = 0; 180 181 CFStringGetBytes(cfstr, CFRangeMake(0, CFStringGetLength(cfstr)), 182 kCFStringEncodingUTF8, 0, is_external, 183 (UInt8 *)str, len - 1, &ret_len); 184 if (str != NULL) { 185 str[ret_len] = '\0'; 186 } 187 return (ret_len + 1); /* leave 1 byte for nul-termination */ 188} 189 190PRIVATE_EXTERN Boolean 191my_CFStringArrayToCStringArray(CFArrayRef arr, void * buffer, int * buffer_size, 192 int * ret_count) 193{ 194 int count = CFArrayGetCount(arr); 195 int i; 196 char * offset = NULL; 197 int space; 198 char * * strlist = NULL; 199 200 space = count * sizeof(char *); 201 if (buffer != NULL) { 202 if (*buffer_size < space) { 203 /* not enough space for even the pointer list */ 204 return (FALSE); 205 } 206 strlist = (char * *)buffer; 207 offset = buffer + space; /* the start of the 1st string */ 208 } 209 for (i = 0; i < count; i++) { 210 CFIndex len = 0; 211 CFStringRef str; 212 213 str = CFArrayGetValueAtIndex(arr, i); 214 if (isA_CFString(str) == NULL) { 215 return (FALSE); 216 } 217 if (buffer != NULL) { 218 len = *buffer_size - space; 219 if (len < 0) { 220 return (FALSE); 221 } 222 } 223 len = my_CFStringToCStringAndLength(str, offset, len); 224 if (buffer != NULL) { 225 strlist[i] = offset; 226 offset += len; 227 } 228 space += len; 229 } 230 *buffer_size = roundup(space, sizeof(char *)); 231 *ret_count = count; 232 return (TRUE); 233} 234 235PRIVATE_EXTERN Boolean 236my_CFStringArrayToEtherArray(CFArrayRef array, char * buffer, int * buffer_size, 237 int * ret_count) 238{ 239 int count = CFArrayGetCount(array); 240 int i; 241 struct ether_addr * list = NULL; 242 int space; 243 244 space = roundup(count * sizeof(*list), sizeof(char *)); 245 if (buffer != NULL) { 246 if (*buffer_size < space) { 247 /* not enough space for all elements */ 248 return (FALSE); 249 } 250 list = (struct ether_addr *)buffer; 251 } 252 for (i = 0; i < count; i++) { 253 struct ether_addr * eaddr; 254 CFStringRef str = CFArrayGetValueAtIndex(array, i); 255 char val[64]; 256 257 if (isA_CFString(str) == NULL) { 258 return (FALSE); 259 } 260 if (CFStringGetCString(str, val, sizeof(val), kCFStringEncodingASCII) 261 == FALSE) { 262 return (FALSE); 263 } 264 eaddr = ether_aton((char *)val); 265 if (eaddr == NULL) { 266 return (FALSE); 267 } 268 if (list != NULL) { 269 list[i] = *eaddr; 270 } 271 } 272 *buffer_size = space; 273 *ret_count = count; 274 return (TRUE); 275} 276 277PRIVATE_EXTERN bool 278my_CFStringToIPAddress(CFStringRef str, struct in_addr * ret_ip) 279{ 280 char buf[64]; 281 282 ret_ip->s_addr = 0; 283 if (isA_CFString(str) == NULL) { 284 return (FALSE); 285 } 286 if (CFStringGetCString(str, buf, sizeof(buf), kCFStringEncodingASCII) 287 == FALSE) { 288 return (FALSE); 289 } 290 if (inet_aton(buf, ret_ip) == 1) { 291 return (TRUE); 292 } 293 return (FALSE); 294} 295 296PRIVATE_EXTERN bool 297my_CFStringToNumber(CFStringRef str, uint32_t * ret_val) 298{ 299 char buf[64]; 300 unsigned long val; 301 302 my_CFStringToCStringAndLength(str, buf, sizeof(buf)); 303 val = strtoul(buf, NULL, 0); 304 if (val != ULONG_MAX && errno != ERANGE) { 305 *ret_val = (uint32_t)val; 306 return (TRUE); 307 } 308 return (FALSE); 309} 310 311PRIVATE_EXTERN bool 312my_CFTypeToNumber(CFTypeRef element, uint32_t * l_p) 313{ 314 if (isA_CFString(element) != NULL) { 315 if (my_CFStringToNumber(element, l_p) == FALSE) { 316 return (FALSE); 317 } 318 } 319 else if (isA_CFBoolean(element) != NULL) { 320 *l_p = CFBooleanGetValue(element); 321 } 322 else if (isA_CFNumber(element) != NULL) { 323 if (CFNumberGetValue(element, kCFNumberSInt32Type, l_p) 324 == FALSE) { 325 return (FALSE); 326 } 327 } 328 else { 329 return (FALSE); 330 } 331 return (TRUE); 332} 333 334PRIVATE_EXTERN void 335my_CFDictionarySetTypeAsArrayValue(CFMutableDictionaryRef dict, 336 CFStringRef prop, CFTypeRef val) 337{ 338 CFArrayRef array; 339 340 array = CFArrayCreate(NULL, (const void **)&val, 1, 341 &kCFTypeArrayCallBacks); 342 if (array != NULL) { 343 CFDictionarySetValue(dict, prop, array); 344 CFRelease(array); 345 } 346 return; 347} 348 349PRIVATE_EXTERN void 350my_CFDictionarySetIPAddressAsArrayValue(CFMutableDictionaryRef dict, 351 CFStringRef prop, 352 struct in_addr ip_addr) 353{ 354 CFStringRef str; 355 356 str = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), 357 IP_LIST(&ip_addr)); 358 my_CFDictionarySetTypeAsArrayValue(dict, prop, str); 359 CFRelease(str); 360 return; 361} 362 363PRIVATE_EXTERN void 364my_CFArrayAppendUniqueValue(CFMutableArrayRef arr, CFTypeRef new) 365{ 366 int count; 367 int i; 368 369 count = CFArrayGetCount(arr); 370 for (i = 0; i < count; i++) { 371 CFStringRef element = CFArrayGetValueAtIndex(arr, i); 372 if (CFEqual(element, new)) { 373 return; 374 } 375 } 376 CFArrayAppendValue(arr, new); 377 return; 378} 379 380PRIVATE_EXTERN Boolean 381my_CFEqual(CFTypeRef val1, CFTypeRef val2) 382{ 383 if (val1 == NULL) { 384 if (val2 == NULL) { 385 return (TRUE); 386 } 387 return (FALSE); 388 } 389 if (val2 == NULL) { 390 return (FALSE); 391 } 392 if (CFGetTypeID(val1) != CFGetTypeID(val2)) { 393 return (FALSE); 394 } 395 return (CFEqual(val1, val2)); 396} 397 398 399/* 400 * Function: my_CFStringCopyComponent 401 * Purpose: 402 * Separates the given string using the given separator, and returns 403 * the component at the specified index. 404 * Returns: 405 * NULL if no such component exists, non-NULL component otherwise 406 */ 407PRIVATE_EXTERN CFStringRef 408my_CFStringCopyComponent(CFStringRef path, CFStringRef separator, 409 CFIndex component_index) 410{ 411 CFArrayRef arr; 412 CFStringRef component = NULL; 413 414 arr = CFStringCreateArrayBySeparatingStrings(NULL, path, separator); 415 if (arr == NULL) { 416 goto done; 417 } 418 if (CFArrayGetCount(arr) <= component_index) { 419 goto done; 420 } 421 component = CFRetain(CFArrayGetValueAtIndex(arr, component_index)); 422 423 done: 424 my_CFRelease(&arr); 425 return (component); 426 427} 428 429CFStringRef 430my_CFStringCreateWithIPAddress(const struct in_addr ip) 431{ 432 return (CFStringCreateWithFormat(NULL, NULL, 433 CFSTR(IP_FORMAT), IP_LIST(&ip))); 434} 435 436CFStringRef 437my_CFStringCreateWithIPv6Address(const void * ip6_addr) 438{ 439 char ntopbuf[INET6_ADDRSTRLEN]; 440 const char * c_str; 441 442 c_str = inet_ntop(AF_INET6, ip6_addr, ntopbuf, sizeof(ntopbuf)); 443 return (CFStringCreateWithCString(NULL, c_str, kCFStringEncodingASCII)); 444} 445 446void 447my_CFStringAppendBytesAsHex(CFMutableStringRef str, const uint8_t * bytes, 448 int length, char separator) 449{ 450 int i; 451 452 for (i = 0; i < length; i++) { 453 char sep[3]; 454 455 if (i == 0) { 456 sep[0] = '\0'; 457 } 458 else { 459 if ((i % 8) == 0 && separator == ' ') { 460 sep[0] = sep[1] = ' '; 461 sep[2] = '\0'; 462 } 463 else { 464 sep[0] = separator; 465 sep[1] = '\0'; 466 } 467 } 468 CFStringAppendFormat(str, NULL, CFSTR("%s%02x"), sep, bytes[i]); 469 } 470 return; 471} 472 473char * 474my_CFStringToCString(CFStringRef cfstr, CFStringEncoding encoding) 475{ 476 CFIndex l; 477 CFRange range; 478 uint8_t * str; 479 480 range = CFRangeMake(0, CFStringGetLength(cfstr)); 481 CFStringGetBytes(cfstr, range, encoding, 482 0, FALSE, NULL, 0, &l); 483 if (l <= 0) { 484 return (NULL); 485 } 486 str = (uint8_t *)malloc(l + 1); 487 CFStringGetBytes(cfstr, range, encoding, 0, FALSE, str, l, &l); 488 str[l] = '\0'; 489 return ((char *)str); 490} 491 492