1/* 2 * Copyright (c) 2000-2008, 2011, 2013, 2014 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 * Modification History 26 * 27 * June 1, 2001 Allan Nathanson <ajn@apple.com> 28 * - public API conversion 29 * 30 * January 8, 2001 Allan Nathanson <ajn@apple.com> 31 * - initial revision 32 */ 33 34 35#include <CoreFoundation/CoreFoundation.h> 36#include <CoreFoundation/CFStringDefaultEncoding.h> // for __CFStringGetUserDefaultEncoding 37#include <SystemConfiguration/SystemConfiguration.h> 38#include <SystemConfiguration/SCValidation.h> 39#include <SystemConfiguration/SCPrivate.h> 40#include "dy_framework.h" 41 42 43#pragma mark ComputerName 44 45 46__private_extern__ CFStringRef 47_SCPreferencesCopyComputerName(SCPreferencesRef prefs, 48 CFStringEncoding *nameEncoding) 49{ 50 CFDictionaryRef dict; 51 CFStringRef name = NULL; 52 CFStringRef path; 53 Boolean tempPrefs = FALSE; 54 55 if (prefs == NULL) { 56 prefs = SCPreferencesCreate(NULL, CFSTR("_SCPreferencesCopyComputerName"), NULL); 57 if (prefs == NULL) { 58 return NULL; 59 } 60 tempPrefs = TRUE; 61 } 62 63 path = CFStringCreateWithFormat(NULL, 64 NULL, 65 CFSTR("/%@/%@"), 66 kSCPrefSystem, 67 kSCCompSystem); 68 dict = SCPreferencesPathGetValue(prefs, path); 69 CFRelease(path); 70 71 if (dict != NULL) { 72 if (isA_CFDictionary(dict)) { 73 name = CFDictionaryGetValue(dict, kSCPropSystemComputerName); 74 name = isA_CFString(name); 75 if (name != NULL) { 76 CFRetain(name); 77 } 78 } 79 80 if (nameEncoding != NULL) { 81 CFNumberRef num; 82 83 num = CFDictionaryGetValue(dict, 84 kSCPropSystemComputerNameEncoding); 85 if (isA_CFNumber(num)) { 86 CFNumberGetValue(num, kCFNumberIntType, nameEncoding); 87 } else { 88 *nameEncoding = CFStringGetSystemEncoding(); 89 } 90 } 91 } 92 93 if (tempPrefs) CFRelease(prefs); 94 _SCErrorSet(name != NULL ? kSCStatusOK : kSCStatusNoKey); 95 return name; 96} 97 98 99CFStringRef 100SCDynamicStoreKeyCreateComputerName(CFAllocatorRef allocator) 101{ 102 return SCDynamicStoreKeyCreate(allocator, 103 CFSTR("%@/%@"), 104 kSCDynamicStoreDomainSetup, 105 kSCCompSystem); 106} 107 108 109CFStringRef 110SCDynamicStoreCopyComputerName(SCDynamicStoreRef store, 111 CFStringEncoding *nameEncoding) 112{ 113 CFDictionaryRef dict = NULL; 114 CFStringRef key; 115 CFStringRef name = NULL; 116 117 key = SCDynamicStoreKeyCreateComputerName(NULL); 118 dict = SCDynamicStoreCopyValue(store, key); 119 CFRelease(key); 120 if (dict == NULL) { 121 /* 122 * Let's try looking in the preferences.plist file until 123 * (a) we add an API to retrieve the name regardless of 124 * where it is stored and 125 * (b) this API is deprecated 126 */ 127 name = _SCPreferencesCopyComputerName(NULL, nameEncoding); 128 goto done; 129 } 130 if (!isA_CFDictionary(dict)) { 131 _SCErrorSet(kSCStatusNoKey); 132 goto done; 133 } 134 135 name = isA_CFString(CFDictionaryGetValue(dict, kSCPropSystemComputerName)); 136 if (name == NULL) { 137 _SCErrorSet(kSCStatusNoKey); 138 goto done; 139 } 140 CFRetain(name); 141 142 if (nameEncoding != NULL) { 143 CFNumberRef num; 144 145 num = CFDictionaryGetValue(dict, 146 kSCPropSystemComputerNameEncoding); 147 if (isA_CFNumber(num)) { 148 CFNumberGetValue(num, kCFNumberIntType, nameEncoding); 149 } else { 150 *nameEncoding = CFStringGetSystemEncoding(); 151 } 152 } 153 154 _SCErrorSet(kSCStatusOK); 155 156 done : 157 158 159 if (dict != NULL) CFRelease(dict); 160 return name; 161} 162 163 164Boolean 165SCPreferencesSetComputerName(SCPreferencesRef prefs, 166 CFStringRef name, 167 CFStringEncoding encoding) 168{ 169 CFDictionaryRef dict; 170 CFMutableDictionaryRef newDict; 171 CFNumberRef num; 172 Boolean ok; 173 CFStringRef path; 174 175 if (name != NULL) { 176 CFIndex len; 177 178 if (!isA_CFString(name)) { 179 _SCErrorSet(kSCStatusInvalidArgument); 180 return FALSE; 181 } 182 183 len = CFStringGetLength(name); 184 if (len == 0) { 185 name = NULL; 186 } 187 } 188 189 path = CFStringCreateWithFormat(NULL, 190 NULL, 191 CFSTR("/%@/%@"), 192 kSCPrefSystem, 193 kSCCompSystem); 194 195 dict = SCPreferencesPathGetValue(prefs, path); 196 if (dict != NULL) { 197 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict); 198 } else { 199 newDict = CFDictionaryCreateMutable(NULL, 200 0, 201 &kCFTypeDictionaryKeyCallBacks, 202 &kCFTypeDictionaryValueCallBacks); 203 } 204 205 if ((name != NULL) && (CFStringGetLength(name) > 0)) { 206 CFDictionarySetValue(newDict, kSCPropSystemComputerName, name); 207 208 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &encoding); 209 CFDictionarySetValue(newDict, kSCPropSystemComputerNameEncoding, num); 210 CFRelease(num); 211 212 CFDictionaryRemoveValue(newDict, kSCPropSystemComputerNameRegion); 213 if (encoding == kCFStringEncodingMacRoman) { 214 UInt32 userEncoding = 0; 215 UInt32 userRegion = 0; 216 217 __CFStringGetUserDefaultEncoding(&userEncoding, &userRegion); 218 if ((userEncoding == kCFStringEncodingMacRoman) && (userRegion != 0)) { 219 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &userRegion); 220 CFDictionarySetValue(newDict, kSCPropSystemComputerNameRegion, num); 221 CFRelease(num); 222 } 223 } 224 } else { 225 CFDictionaryRemoveValue(newDict, kSCPropSystemComputerName); 226 CFDictionaryRemoveValue(newDict, kSCPropSystemComputerNameEncoding); 227 CFDictionaryRemoveValue(newDict, kSCPropSystemComputerNameRegion); 228 } 229 230 if (CFDictionaryGetCount(newDict) > 0) { 231 ok = SCPreferencesPathSetValue(prefs, path, newDict); 232 } else { 233 ok = SCPreferencesPathRemoveValue(prefs, path); 234 } 235 236 CFRelease(path); 237 CFRelease(newDict); 238 239 return ok; 240} 241 242 243#pragma mark - 244#pragma mark HostName 245 246 247CFStringRef 248SCPreferencesGetHostName(SCPreferencesRef prefs) 249{ 250 CFDictionaryRef dict; 251 CFStringRef name; 252 CFStringRef path; 253 254 path = CFStringCreateWithFormat(NULL, 255 NULL, 256 CFSTR("/%@/%@"), 257 kSCPrefSystem, 258 kSCCompSystem); 259 dict = SCPreferencesPathGetValue(prefs, path); 260 CFRelease(path); 261 262 if (!isA_CFDictionary(dict)) { 263 _SCErrorSet(kSCStatusNoKey); 264 return NULL; 265 } 266 267 name = isA_CFString(CFDictionaryGetValue(dict, kSCPropSystemHostName)); 268 if (name == NULL) { 269 _SCErrorSet(kSCStatusNoKey); 270 return NULL; 271 } 272 273 return name; 274} 275 276 277Boolean 278SCPreferencesSetHostName(SCPreferencesRef prefs, 279 CFStringRef name) 280{ 281 CFDictionaryRef dict; 282 CFMutableDictionaryRef newDict; 283 Boolean ok; 284 CFStringRef path; 285 286 if (name != NULL) { 287 CFIndex len; 288 289 if (!isA_CFString(name)) { 290 _SCErrorSet(kSCStatusInvalidArgument); 291 return FALSE; 292 } 293 294 len = CFStringGetLength(name); 295 if (len == 0) { 296 name = NULL; 297 } 298 } 299 300 path = CFStringCreateWithFormat(NULL, 301 NULL, 302 CFSTR("/%@/%@"), 303 kSCPrefSystem, 304 kSCCompSystem); 305 306 dict = SCPreferencesPathGetValue(prefs, path); 307 if (dict != NULL) { 308 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict); 309 } else { 310 newDict = CFDictionaryCreateMutable(NULL, 311 0, 312 &kCFTypeDictionaryKeyCallBacks, 313 &kCFTypeDictionaryValueCallBacks); 314 } 315 316 if (name != NULL) { 317 CFDictionarySetValue(newDict, kSCPropSystemHostName, name); 318 } else { 319 CFDictionaryRemoveValue(newDict, kSCPropSystemHostName); 320 } 321 322 if (CFDictionaryGetCount(newDict) > 0) { 323 ok = SCPreferencesPathSetValue(prefs, path, newDict); 324 } else { 325 ok = SCPreferencesPathRemoveValue(prefs, path); 326 } 327 328 CFRelease(path); 329 CFRelease(newDict); 330 331 return ok; 332} 333 334 335#pragma mark - 336#pragma mark LocalHostName 337 338 339__private_extern__ CFStringRef 340_SCPreferencesCopyLocalHostName(SCPreferencesRef prefs) 341{ 342 CFDictionaryRef dict; 343 CFStringRef name = NULL; 344 CFStringRef path; 345 Boolean tempPrefs = FALSE; 346 347 if (prefs == NULL) { 348 prefs = SCPreferencesCreate(NULL, CFSTR("_SCPreferencesCopyLocalHostName"), NULL); 349 if (prefs == NULL) { 350 return NULL; 351 } 352 tempPrefs = TRUE; 353 } 354 355 path = CFStringCreateWithFormat(NULL, 356 NULL, 357 CFSTR("/%@/%@/%@"), 358 kSCPrefSystem, 359 kSCCompNetwork, 360 kSCCompHostNames); 361 dict = SCPreferencesPathGetValue(prefs, path); 362 CFRelease(path); 363 364 if (dict != NULL) { 365 if (isA_CFDictionary(dict)) { 366 name = CFDictionaryGetValue(dict, kSCPropNetLocalHostName); 367 name = isA_CFString(name); 368 if (name != NULL) { 369 CFRetain(name); 370 } 371 } 372 } 373 374 if (tempPrefs) CFRelease(prefs); 375 _SCErrorSet(name != NULL ? kSCStatusOK : kSCStatusNoKey); 376 return name; 377} 378 379 380CFStringRef 381SCDynamicStoreKeyCreateHostNames(CFAllocatorRef allocator) 382{ 383 return SCDynamicStoreKeyCreate(allocator, 384 CFSTR("%@/%@/%@"), 385 kSCDynamicStoreDomainSetup, 386 kSCCompNetwork, 387 kSCCompHostNames); 388} 389 390 391CFStringRef 392SCDynamicStoreCopyLocalHostName(SCDynamicStoreRef store) 393{ 394 CFDictionaryRef dict = NULL; 395 CFStringRef key; 396 CFStringRef name = NULL; 397 398 key = SCDynamicStoreKeyCreateHostNames(NULL); 399 dict = SCDynamicStoreCopyValue(store, key); 400 CFRelease(key); 401 if (dict == NULL) { 402 /* 403 * Let's try looking in the preferences.plist file until 404 * (a) we add an API to retrieve the name regardless of 405 * where it is stored and 406 * (b) this API is deprecated 407 */ 408 name = _SCPreferencesCopyLocalHostName(NULL); 409 goto done; 410 } 411 if (!isA_CFDictionary(dict)) { 412 _SCErrorSet(kSCStatusNoKey); 413 goto done; 414 } 415 416 name = isA_CFString(CFDictionaryGetValue(dict, kSCPropNetLocalHostName)); 417 if (name == NULL) { 418 _SCErrorSet(kSCStatusNoKey); 419 goto done; 420 } 421 CFRetain(name); 422 423 _SCErrorSet(kSCStatusOK); 424 425 done : 426 427 428 if (dict != NULL) CFRelease(dict); 429 return name; 430} 431 432 433Boolean 434_SC_stringIsValidDNSName(const char *name) 435{ 436 int i; 437 size_t len = strlen(name); 438 char prev = '\0'; 439 const char *scan; 440 441 if (len == 0) { 442 return FALSE; 443 } 444 445 for (scan = name, i = 0; i < len; i++, scan++) { 446 char ch = *scan; 447 char next = *(scan + 1); 448 449 if (prev == '.' || prev == '\0') { 450 if (isalnum(ch) == 0) { 451 /* a label must begin with a letter or digit */ 452 return FALSE; 453 } 454 } else if (next == '\0' || next == '.') { 455 if (isalnum(ch) == 0) { 456 /* a label must end with a letter or digit */ 457 return FALSE; 458 } 459 } else if (isalnum(ch) == 0) { 460 switch (ch) { 461 case '.': 462 if (prev == '.') { 463 /* no empty labels */ 464 return FALSE; 465 } 466 break; 467 case '-': 468 /* hyphens are OK within a label */ 469 break; 470 default: 471 /* an invalid character */ 472 return FALSE; 473 break; 474 } 475 } 476 prev = ch; 477 } 478 479 return TRUE; 480} 481 482 483Boolean 484_SC_CFStringIsValidDNSName(CFStringRef name) 485{ 486 Boolean clean = FALSE; 487 char *str = NULL; 488 489 if (!isA_CFString(name)) { 490 return FALSE; 491 } 492 493 str = _SC_cfstring_to_cstring(name, NULL, 0, kCFStringEncodingASCII); 494 if (str == NULL) { 495 return FALSE; 496 } 497 498 clean = _SC_stringIsValidDNSName(str); 499 500 if (str != NULL) CFAllocatorDeallocate(NULL, str); 501 return clean; 502} 503 504 505Boolean 506SCPreferencesSetLocalHostName(SCPreferencesRef prefs, 507 CFStringRef name) 508{ 509 CFDictionaryRef dict; 510 CFMutableDictionaryRef newDict; 511 Boolean ok; 512 CFStringRef path; 513 514 if (name != NULL) { 515 CFIndex len; 516 517 if (!isA_CFString(name)) { 518 _SCErrorSet(kSCStatusInvalidArgument); 519 return FALSE; 520 } 521 522 len = CFStringGetLength(name); 523 if (len > 0) { 524 if (!_SC_CFStringIsValidDNSName(name)) { 525 _SCErrorSet(kSCStatusInvalidArgument); 526 return FALSE; 527 } 528 529 if (CFStringFindWithOptions(name, CFSTR("."), CFRangeMake(0, len), 0, NULL)) { 530 _SCErrorSet(kSCStatusInvalidArgument); 531 return FALSE; 532 } 533 } else { 534 name = NULL; 535 } 536 } 537 538 path = CFStringCreateWithFormat(NULL, 539 NULL, 540 CFSTR("/%@/%@/%@"), 541 kSCPrefSystem, 542 kSCCompNetwork, 543 kSCCompHostNames); 544 545 dict = SCPreferencesPathGetValue(prefs, path); 546 if (dict != NULL) { 547 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict); 548 } else { 549 newDict = CFDictionaryCreateMutable(NULL, 550 0, 551 &kCFTypeDictionaryKeyCallBacks, 552 &kCFTypeDictionaryValueCallBacks); 553 } 554 555 if (name != NULL) { 556 CFDictionarySetValue(newDict, kSCPropNetLocalHostName, name); 557 } else { 558 CFDictionaryRemoveValue(newDict, kSCPropNetLocalHostName); 559 } 560 561 if (CFDictionaryGetCount(newDict) > 0) { 562 ok = SCPreferencesPathSetValue(prefs, path, newDict); 563 } else { 564 ok = SCPreferencesPathRemoveValue(prefs, path); 565 } 566 567 CFRelease(path); 568 CFRelease(newDict); 569 570 return ok; 571} 572 573 574Boolean 575_SC_CFStringIsValidNetBIOSName(CFStringRef name) 576{ 577 if (!isA_CFString(name)) { 578 return FALSE; 579 } 580 581 if (CFStringGetLength(name) > 15) { 582 return FALSE; 583 } 584 585 return TRUE; 586} 587