2 * Copyright (c) 2001, 2003-2005, 2011, 2013 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
28 #include "SystemConfiguration.h"
29 #include "SCValidation.h"
30 #include "SCDynamicStoreCopyDHCPInfo.h"
31 #include "DHCPClientPreferences.h"
33 #define DHCPCLIENT_PREFERENCES_ID "DHCPClient.xml"
34 #define DHCPCLIENT_APPLICATION_PREF "Application"
36 #define DHCP_REQUESTED_PARAMETER_LIST "DHCPRequestedParameterList"
39 ** DHCPClientPreferences{Set,Get}ApplicationOptions()
42 S_get_char_array(CFArrayRef arr
, CFIndex
* len
)
50 count
= CFArrayGetCount(arr
);
59 for (i
= 0, real_count
= 0; i
< count
; i
++) {
60 CFNumberRef n
= isA_CFNumber(CFArrayGetValueAtIndex(arr
, i
));
63 if (n
&& CFNumberGetValue(n
, kCFNumberIntType
, &val
)) {
64 buf
[real_count
++] = (UInt8
) val
;
70 if (count
== 0 && buf
) {
78 my_CFArrayAppendUniqueValue(CFMutableArrayRef arr
, CFTypeRef
new)
81 CFIndex n
= CFArrayGetCount(arr
);
83 for (i
= 0; i
< n
; i
++) {
84 CFStringRef element
= CFArrayGetValueAtIndex(arr
, i
);
85 if (CFEqual(element
, new)) {
89 CFArrayAppendValue(arr
, new);
93 static __inline__ CF_RETURNS_RETAINED CFStringRef
94 S_application_path(CFStringRef applicationID
)
96 return (CFStringCreateWithFormat(NULL
, NULL
,
97 CFSTR("/" DHCPCLIENT_APPLICATION_PREF
103 DHCPClientPreferencesSetApplicationOptions(CFStringRef applicationID
,
107 CFMutableDictionaryRef dict
= NULL
;
108 CFStringRef path
= NULL
;
109 SCPreferencesRef prefs
= NULL
;
110 Boolean success
= FALSE
;
112 if (applicationID
== NULL
) {
115 path
= S_application_path(applicationID
);
119 prefs
= SCPreferencesCreate(NULL
, CFSTR("DHCPClientSetAppReqParams"),
120 CFSTR(DHCPCLIENT_PREFERENCES_ID
));
124 dict
= (CFMutableDictionaryRef
)SCPreferencesPathGetValue(prefs
, path
);
126 dict
= CFDictionaryCreateMutable(NULL
, 0,
127 &kCFTypeDictionaryKeyCallBacks
,
128 &kCFTypeDictionaryValueCallBacks
);
131 dict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
136 if (options
&& count
> 0) {
138 CFMutableArrayRef array
;
140 array
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
144 for (i
= 0; i
< count
; i
++) {
148 if (options
[i
] == 0 || options
[i
] == 255) {
149 /* ignore pads and end */
153 number
= CFNumberCreate(NULL
, kCFNumberIntType
, &val
);
154 if (number
== NULL
) {
158 my_CFArrayAppendUniqueValue(array
, number
);
161 CFDictionarySetValue(dict
, CFSTR(DHCP_REQUESTED_PARAMETER_LIST
),
166 CFDictionaryRemoveValue(dict
, CFSTR(DHCP_REQUESTED_PARAMETER_LIST
));
168 if (SCPreferencesLock(prefs
, TRUE
)) {
169 success
= SCPreferencesPathSetValue(prefs
, path
, dict
);
171 success
= SCPreferencesCommitChanges(prefs
);
173 (void)SCPreferencesApplyChanges(prefs
);
176 (void)SCPreferencesUnlock(prefs
);
192 DHCPClientPreferencesCopyApplicationOptions(CFStringRef applicationID
,
195 CFDictionaryRef dict
= NULL
;
196 UInt8
* options
= NULL
;
198 CFStringRef path
= NULL
;
199 SCPreferencesRef prefs
= NULL
;
201 if (applicationID
== NULL
) {
204 path
= S_application_path(applicationID
);
208 prefs
= SCPreferencesCreate(NULL
, CFSTR("DHCPClientCopyAppReqParams"),
209 CFSTR(DHCPCLIENT_PREFERENCES_ID
));
213 dict
= SCPreferencesPathGetValue(prefs
, path
);
217 parms
= CFDictionaryGetValue(dict
,
218 CFSTR(DHCP_REQUESTED_PARAMETER_LIST
));
219 if (isA_CFArray(parms
) == NULL
) {
222 options
= S_get_char_array(parms
, count
);
239 SCDynamicStoreCopyDHCPInfo(SCDynamicStoreRef store
, CFStringRef serviceID
)
241 CFDictionaryRef dhcp_dict
= NULL
;
242 CFStringRef key
= NULL
;
243 CFDictionaryRef primary_dict
= NULL
;
245 if (serviceID
== NULL
) {
246 /* get the primary service name */
247 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,
248 kSCDynamicStoreDomainState
,
251 primary_dict
= SCDynamicStoreCopyValue(store
, key
);
253 serviceID
= CFDictionaryGetValue(primary_dict
,
254 kSCDynamicStorePropNetPrimaryService
);
259 if (serviceID
== NULL
) {
262 key
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
263 kSCDynamicStoreDomainState
,
267 dhcp_dict
= SCDynamicStoreCopyValue(store
, key
);
268 if (dhcp_dict
!= NULL
269 && isA_CFDictionary(dhcp_dict
) == NULL
) {
270 CFRelease(dhcp_dict
);
277 CFRelease(primary_dict
);
283 DHCPInfoGetOptionData(CFDictionaryRef dhcp_dict
, UInt8 code
)
285 CFDataRef data
= NULL
;
286 CFStringRef option_code_str
= NULL
;
288 option_code_str
= CFStringCreateWithFormat(NULL
, NULL
,
289 CFSTR("Option_%d"), code
);
290 if (option_code_str
== NULL
) {
294 data
= CFDictionaryGetValue(dhcp_dict
, option_code_str
);
295 data
= isA_CFData(data
);
298 CFRelease(option_code_str
);
303 DHCPInfoGetLeaseStartTime(CFDictionaryRef dhcp_dict
)
305 return (CFDictionaryGetValue(dhcp_dict
, CFSTR("LeaseStartTime")));
309 DHCPInfoGetLeaseExpirationTime(CFDictionaryRef dhcp_dict
)
311 return (CFDictionaryGetValue(dhcp_dict
, CFSTR("LeaseExpirationTime")));
314 #ifdef TEST_DHCPCLIENT_PREFERENCES
316 print_data(u_char
* data_p
, int n_bytes
)
318 #define CHARS_PER_LINE 16
319 char line_buf
[CHARS_PER_LINE
+ 1];
323 for (line_pos
= 0, offset
= 0; offset
< n_bytes
; offset
++, data_p
++) {
325 printf("%04x ", offset
);
327 line_buf
[line_pos
] = isprint(*data_p
) ? *data_p
: '.';
328 printf(" %02x", *data_p
);
330 if (line_pos
== CHARS_PER_LINE
) {
331 line_buf
[CHARS_PER_LINE
] = '\0';
332 printf(" %s\n", line_buf
);
335 else if (line_pos
== (CHARS_PER_LINE
/ 2))
338 if (line_pos
) { /* need to finish up the line */
339 for (; line_pos
< CHARS_PER_LINE
; line_pos
++) {
341 line_buf
[line_pos
] = ' ';
343 line_buf
[CHARS_PER_LINE
] = '\0';
344 printf(" %s\n", line_buf
);
348 #define CMDSTR_GETOPTION "getoption"
349 #define CMDSTR_LEASE "leaseinfo"
350 #define CMDSTR_GETPARAMS "getparams"
351 #define CMDSTR_SETPARAMS "setparams"
353 static __inline__
void
354 S_print_char_array(UInt8
* params
, int n_params
)
358 for (i
= 0; i
< n_params
; i
++) {
360 printf("%d", params
[i
]);
362 printf(", %d", params
[i
]);
370 printf("%s " CMDSTR_GETOPTION
" <serviceID> <opt> [ <type> ]\n"
371 "%s " CMDSTR_LEASE
" <serviceID>\n"
372 "%s " CMDSTR_GETPARAMS
" <app_id>\n"
373 "%s " CMDSTR_SETPARAMS
" <app_id> [ <opt> [ <opt> ] ... [ <opt> ] ] ]\n"
375 " <serviceID> : service ID string | \"\"\n"
376 " <opt> : DHCP/BOOTP option code\n"
377 " (e.g. 1 == subnet mask, 3 == router, 6 = dns, 15 = domain)\n"
378 " <type> : type of option: string, ip\n"
379 " <app_id> : application id (e.g. com.apple.ntpd, com.thursby.Dave)\n",
380 prog
, prog
, prog
, prog
);
385 dump_gregorian_date(CFGregorianDate d
)
387 printf("%d/%d/%d %02d:%02d:%02d\n",
388 (int)d
.year
, d
.month
, d
.day
, d
.hour
, d
.minute
, (int)d
.second
);
393 show_date(CFAbsoluteTime t
)
396 static CFTimeZoneRef tz
= NULL
;
399 tz
= CFTimeZoneCopySystem();
402 d
= CFAbsoluteTimeGetGregorianDate(t
, tz
);
403 dump_gregorian_date(d
);
407 #define IP_FORMAT "%d.%d.%d.%d"
408 #define IP_CH(ip, i) (((u_char *)(ip))[i])
409 #define IP_LIST(ip) IP_CH(ip,0),IP_CH(ip,1),IP_CH(ip,2),IP_CH(ip,3)
420 main(int argc
, char * argv
[])
423 command_t command
= command_none_e
;
426 CFDictionaryRef info
;
428 CFStringRef serviceID
= NULL
;
430 command_str
= argv
[1];
433 if (strcmp(command_str
, CMDSTR_GETOPTION
) == 0) {
434 if (argc
< 4 || argc
> 5) {
437 command
= command_getoption_e
;
439 else if (strcmp(command_str
, CMDSTR_LEASE
) == 0) {
443 command
= command_lease_e
;
445 else if (strcmp(command_str
, CMDSTR_SETPARAMS
) == 0) {
446 command
= command_setparams_e
;
451 else if (strcmp(command_str
, CMDSTR_GETPARAMS
) == 0) {
452 command
= command_getparams_e
;
462 case command_getoption_e
: {
466 boolean_t printed
= FALSE
;
471 serviceID
= CFStringCreateWithFormat(NULL
, NULL
,
472 CFSTR("%s"), argv
[2]);
475 info
= SCDynamicStoreCopyDHCPInfo(NULL
, serviceID
);
484 code
= atoi(code_str
);
486 option
= DHCPInfoGetOptionData(info
, code
);
487 if (option
== NULL
) {
490 len
= CFDataGetLength(option
);
493 if (strcmp(type
, "ip") == 0) {
495 const void * ptr
= CFDataGetBytePtr(option
);
499 printf(IP_FORMAT
, IP_LIST(ptr
));
502 printf(" " IP_FORMAT
, IP_LIST(ptr
));
510 else if (strcmp(type
, "string") == 0) {
511 printf("%.*s\n", (int)len
, (char *)CFDataGetBytePtr(option
));
517 if (printed
== FALSE
) {
518 print_data((void *)CFDataGetBytePtr(option
), len
);
521 CFRelease(serviceID
);
525 case command_lease_e
: {
529 serviceID
= CFStringCreateWithFormat(NULL
, NULL
,
530 CFSTR("%s"), argv
[2]);
533 info
= SCDynamicStoreCopyDHCPInfo(NULL
, serviceID
);
537 start
= DHCPInfoGetLeaseStartTime(info
);
543 #define OPTION_LEASE_TIME 51
545 option
= DHCPInfoGetOptionData(info
, OPTION_LEASE_TIME
);
546 if (option
== NULL
) {
547 fprintf(stderr
, "what, no lease time?\n");
550 printf("Lease start: ");
551 show_date(CFDateGetAbsoluteTime(start
));
552 lease
= ntohl(*((int32_t *)CFDataGetBytePtr(option
)));
553 if (lease
== 0xffffffff) {
554 printf("Lease is infinite\n");
557 printf("Lease expires: ");
558 show_date(lease
+ CFDateGetAbsoluteTime(start
));
560 option
= DHCPInfoGetOptionData(info
, SERVER_ID
);
562 printf("Server IP: " IP_FORMAT
"\n",
563 IP_LIST(CFDataGetBytePtr(option
)));
567 printf("no lease\n");
570 CFRelease(serviceID
);
574 case command_getparams_e
: {
575 app_id
= CFStringCreateWithFormat(NULL
, NULL
,
576 CFSTR("%s"), argv
[2]);
577 params
= DHCPClientPreferencesCopyApplicationOptions(app_id
, &count
);
579 printf("%s params = {", argv
[2]);
580 S_print_char_array(params
, count
);
586 case command_setparams_e
: {
588 UInt8
* options
= NULL
;
594 options
= malloc(count
);
595 if (options
== NULL
) {
596 fprintf(stderr
, "malloc failed %s\n",
600 for (i
= 0; i
< count
; i
++) {
601 options
[i
] = atoi(argv
[3 + i
]);
604 app_id
= CFStringCreateWithFormat(NULL
, NULL
,
605 CFSTR("%s"), argv
[2]);
606 if (DHCPClientPreferencesSetApplicationOptions(app_id
, options
,
608 printf("operation failed\n");
621 #endif // TEST_DHCPCLIENT_PREFERENCES