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