]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/DHCP.c
configd-963.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / DHCP.c
1 /*
2 * Copyright (c) 2001, 2003-2005, 2011, 2013, 2015, 2017 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 #include <stdio.h>
25 #include <unistd.h>
26
27
28 #include "SystemConfiguration.h"
29 #include "SCValidation.h"
30 #include "SCDynamicStoreCopyDHCPInfo.h"
31 #include "DHCPClientPreferences.h"
32
33 #define DHCPCLIENT_PREFERENCES_ID "DHCPClient.xml"
34 #define DHCPCLIENT_APPLICATION_PREF "Application"
35
36 #define DHCP_REQUESTED_PARAMETER_LIST "DHCPRequestedParameterList"
37
38 /**
39 ** DHCPClientPreferences{Set,Get}ApplicationOptions()
40 **/
41 static UInt8 *
42 S_get_char_array(CFArrayRef arr, CFIndex * len)
43 {
44 UInt8 * buf = NULL;
45 CFIndex count = 0;
46 CFIndex i;
47 CFIndex real_count;
48
49 if (arr) {
50 count = CFArrayGetCount(arr);
51 }
52 if (count == 0) {
53 goto done;
54 }
55 buf = malloc(count);
56 if (buf == NULL) {
57 goto done;
58 }
59 for (i = 0, real_count = 0; i < count; i++) {
60 CFNumberRef n = isA_CFNumber(CFArrayGetValueAtIndex(arr, i));
61 int val;
62
63 if (n && CFNumberGetValue(n, kCFNumberIntType, &val)) {
64 buf[real_count++] = (UInt8) val;
65 }
66 }
67 count = real_count;
68 done:
69 *len = count;
70 if (count == 0 && buf) {
71 free(buf);
72 buf = NULL;
73 }
74 return (buf);
75 }
76
77 static void
78 my_CFArrayAppendUniqueValue(CFMutableArrayRef arr, CFTypeRef new)
79 {
80 CFIndex i;
81 CFIndex n = CFArrayGetCount(arr);
82
83 for (i = 0; i < n; i++) {
84 CFStringRef element = CFArrayGetValueAtIndex(arr, i);
85 if (CFEqual(element, new)) {
86 return;
87 }
88 }
89 CFArrayAppendValue(arr, new);
90 return;
91 }
92
93 static __inline__ CF_RETURNS_RETAINED CFStringRef
94 S_application_path(CFStringRef applicationID)
95 {
96 return (CFStringCreateWithFormat(NULL, NULL,
97 CFSTR("/" DHCPCLIENT_APPLICATION_PREF
98 "/%@"),
99 applicationID));
100 }
101
102 Boolean
103 DHCPClientPreferencesSetApplicationOptions(CFStringRef applicationID,
104 const UInt8 * options,
105 CFIndex count)
106 {
107 CFMutableDictionaryRef dict = NULL;
108 CFStringRef path = NULL;
109 SCPreferencesRef prefs = NULL;
110 Boolean success = FALSE;
111
112 if (applicationID == NULL) {
113 goto done;
114 }
115 path = S_application_path(applicationID);
116 if (path == NULL) {
117 goto done;
118 }
119 prefs = SCPreferencesCreate(NULL, CFSTR("DHCPClientSetAppReqParams"),
120 CFSTR(DHCPCLIENT_PREFERENCES_ID));
121 if (prefs == NULL) {
122 goto done;
123 }
124 dict = (CFMutableDictionaryRef)SCPreferencesPathGetValue(prefs, path);
125 if (dict == NULL) {
126 dict = CFDictionaryCreateMutable(NULL, 0,
127 &kCFTypeDictionaryKeyCallBacks,
128 &kCFTypeDictionaryValueCallBacks);
129 }
130 else {
131 dict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
132 }
133 if (dict == NULL) {
134 goto done;
135 }
136 if (options && count > 0) {
137 int i;
138 CFMutableArrayRef array;
139
140 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
141 if (array == NULL) {
142 goto done;
143 }
144 for (i = 0; i < count; i++) {
145 int val;
146 CFNumberRef number;
147
148 if (options[i] == 0 || options[i] == 255) {
149 /* ignore pads and end */
150 continue;
151 }
152 val = options[i];
153 number = CFNumberCreate(NULL, kCFNumberIntType, &val);
154 if (number == NULL) {
155 CFRelease(array);
156 goto done;
157 }
158 my_CFArrayAppendUniqueValue(array, number);
159 CFRelease(number);
160 }
161 CFDictionarySetValue(dict, CFSTR(DHCP_REQUESTED_PARAMETER_LIST),
162 array);
163 CFRelease(array);
164 }
165 else {
166 CFDictionaryRemoveValue(dict, CFSTR(DHCP_REQUESTED_PARAMETER_LIST));
167 }
168 if (SCPreferencesLock(prefs, TRUE)) {
169 success = SCPreferencesPathSetValue(prefs, path, dict);
170 if (success) {
171 success = SCPreferencesCommitChanges(prefs);
172 if (success) {
173 (void)SCPreferencesApplyChanges(prefs);
174 }
175 }
176 (void)SCPreferencesUnlock(prefs);
177 }
178 done:
179 if (prefs) {
180 CFRelease(prefs);
181 }
182 if (path) {
183 CFRelease(path);
184 }
185 if (dict) {
186 CFRelease(dict);
187 }
188 return (success);
189 }
190
191 UInt8 *
192 DHCPClientPreferencesCopyApplicationOptions(CFStringRef applicationID,
193 CFIndex * count)
194 {
195 CFDictionaryRef dict = NULL;
196 UInt8 * options = NULL;
197 CFArrayRef parms;
198 CFStringRef path = NULL;
199 SCPreferencesRef prefs = NULL;
200
201 if (applicationID == NULL) {
202 goto done;
203 }
204 path = S_application_path(applicationID);
205 if (path == NULL) {
206 goto done;
207 }
208 prefs = SCPreferencesCreate(NULL, CFSTR("DHCPClientCopyAppReqParams"),
209 CFSTR(DHCPCLIENT_PREFERENCES_ID));
210 if (prefs == NULL) {
211 goto done;
212 }
213 dict = SCPreferencesPathGetValue(prefs, path);
214 if (dict == NULL) {
215 goto done;
216 }
217 parms = CFDictionaryGetValue(dict,
218 CFSTR(DHCP_REQUESTED_PARAMETER_LIST));
219 if (isA_CFArray(parms) == NULL) {
220 goto done;
221 }
222 options = S_get_char_array(parms, count);
223
224 done:
225 if (prefs) {
226 CFRelease(prefs);
227 }
228 if (path) {
229 CFRelease(path);
230 }
231 return (options);
232 }
233
234 /**
235 ** DHCPClientInfo*()
236 **/
237
238 CFDictionaryRef
239 SCDynamicStoreCopyDHCPInfo(SCDynamicStoreRef store, CFStringRef serviceID)
240 {
241 CFDictionaryRef dhcp_dict = NULL;
242 CFStringRef key = NULL;
243 CFDictionaryRef primary_dict = NULL;
244
245 if (serviceID == NULL) {
246 /* get the primary service name */
247 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
248 kSCDynamicStoreDomainState,
249 kSCEntNetIPv4);
250 if (key) {
251 primary_dict = SCDynamicStoreCopyValue(store, key);
252 if (primary_dict) {
253 serviceID = CFDictionaryGetValue(primary_dict,
254 kSCDynamicStorePropNetPrimaryService);
255 }
256 CFRelease(key);
257 }
258 }
259 if (serviceID == NULL) {
260 goto done;
261 }
262 key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
263 kSCDynamicStoreDomainState,
264 serviceID,
265 kSCEntNetDHCP);
266 if (key) {
267 dhcp_dict = SCDynamicStoreCopyValue(store, key);
268 if (dhcp_dict != NULL
269 && isA_CFDictionary(dhcp_dict) == NULL) {
270 CFRelease(dhcp_dict);
271 dhcp_dict = NULL;
272 }
273 CFRelease(key);
274 }
275 done:
276 if (primary_dict) {
277 CFRelease(primary_dict);
278 }
279 return (dhcp_dict);
280 }
281
282 CFDataRef
283 DHCPInfoGetOptionData(CFDictionaryRef dhcp_dict, UInt8 code)
284 {
285 CFDataRef data = NULL;
286 CFStringRef option_code_str = NULL;
287
288 option_code_str = CFStringCreateWithFormat(NULL, NULL,
289 CFSTR("Option_%d"), code);
290 if (option_code_str == NULL) {
291 goto done;
292 }
293
294 data = CFDictionaryGetValue(dhcp_dict, option_code_str);
295 data = isA_CFData(data);
296 done:
297 if (option_code_str)
298 CFRelease(option_code_str);
299 return (data);
300 }
301
302 CFDateRef
303 DHCPInfoGetLeaseStartTime(CFDictionaryRef dhcp_dict)
304 {
305 return (CFDictionaryGetValue(dhcp_dict, CFSTR("LeaseStartTime")));
306 }
307
308 CFDateRef
309 DHCPInfoGetLeaseExpirationTime(CFDictionaryRef dhcp_dict)
310 {
311 return (CFDictionaryGetValue(dhcp_dict, CFSTR("LeaseExpirationTime")));
312 }
313
314 #ifdef TEST_DHCPCLIENT_PREFERENCES
315 void
316 print_data(u_char * data_p, int n_bytes)
317 {
318 #define CHARS_PER_LINE 16
319 char line_buf[CHARS_PER_LINE + 1];
320 int line_pos;
321 int offset;
322
323 for (line_pos = 0, offset = 0; offset < n_bytes; offset++, data_p++) {
324 if (line_pos == 0)
325 printf("%04x ", offset);
326
327 line_buf[line_pos] = isprint(*data_p) ? *data_p : '.';
328 printf(" %02x", *data_p);
329 line_pos++;
330 if (line_pos == CHARS_PER_LINE) {
331 line_buf[CHARS_PER_LINE] = '\0';
332 printf(" %s\n", line_buf);
333 line_pos = 0;
334 }
335 else if (line_pos == (CHARS_PER_LINE / 2))
336 printf(" ");
337 }
338 if (line_pos) { /* need to finish up the line */
339 for (; line_pos < CHARS_PER_LINE; line_pos++) {
340 printf(" ");
341 line_buf[line_pos] = ' ';
342 }
343 line_buf[CHARS_PER_LINE] = '\0';
344 printf(" %s\n", line_buf);
345 }
346 }
347
348 #define CMDSTR_GETOPTION "getoption"
349 #define CMDSTR_LEASE "leaseinfo"
350 #define CMDSTR_GETPARAMS "getparams"
351 #define CMDSTR_SETPARAMS "setparams"
352
353 static __inline__ void
354 S_print_char_array(UInt8 * params, int n_params)
355 {
356 int i;
357
358 for (i = 0; i < n_params; i++) {
359 if (i == 0)
360 printf("%d", params[i]);
361 else
362 printf(", %d", params[i]);
363 }
364 return;
365 }
366
367 void
368 usage(char * prog)
369 {
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"
374 "where:\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);
381 exit(0);
382 }
383
384 static void
385 dump_gregorian_date(CFGregorianDate d)
386 {
387 printf("%d/%d/%d %02d:%02d:%02d\n",
388 (int)d.year, d.month, d.day, d.hour, d.minute, (int)d.second);
389 return;
390 }
391
392 static void
393 show_date(CFAbsoluteTime t)
394 {
395 CFGregorianDate d;
396 static CFTimeZoneRef tz = NULL;
397
398 if (tz == NULL) {
399 tz = CFTimeZoneCopySystem();
400 }
401
402 d = CFAbsoluteTimeGetGregorianDate(t, tz);
403 dump_gregorian_date(d);
404 return;
405 }
406
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)
410
411 typedef enum {
412 command_none_e,
413 command_getoption_e,
414 command_lease_e,
415 command_setparams_e,
416 command_getparams_e,
417 } command_t;
418
419 int
420 main(int argc, char * argv[])
421 {
422 CFStringRef app_id;
423 command_t command = command_none_e;
424 char * command_str;
425 CFIndex count;
426 CFDictionaryRef info;
427 UInt8 * params;
428 CFStringRef serviceID = NULL;
429
430 command_str = argv[1];
431 if (argc < 2)
432 usage(argv[0]);
433 if (strcmp(command_str, CMDSTR_GETOPTION) == 0) {
434 if (argc < 4 || argc > 5) {
435 usage(argv[0]);
436 }
437 command = command_getoption_e;
438 }
439 else if (strcmp(command_str, CMDSTR_LEASE) == 0) {
440 if (argc != 3) {
441 usage(argv[0]);
442 }
443 command = command_lease_e;
444 }
445 else if (strcmp(command_str, CMDSTR_SETPARAMS) == 0) {
446 command = command_setparams_e;
447 if (argc < 3) {
448 usage(argv[0]);
449 }
450 }
451 else if (strcmp(command_str, CMDSTR_GETPARAMS) == 0) {
452 command = command_getparams_e;
453 if (argc != 3) {
454 usage(argv[0]);
455 }
456 }
457 else {
458 usage(argv[0]);
459 }
460
461 switch (command) {
462 case command_getoption_e: {
463 UInt8 code;
464 char * code_str;
465 CFDataRef option;
466 boolean_t printed = FALSE;
467 CFIndex len;
468 char * type = NULL;
469
470 if (argv[2][0]) {
471 serviceID = CFStringCreateWithFormat(NULL, NULL,
472 CFSTR("%s"), argv[2]);
473 }
474
475 info = SCDynamicStoreCopyDHCPInfo(NULL, serviceID);
476 if (info == NULL) {
477 exit(1);
478 }
479
480 code_str = argv[3];
481 if (argc > 4) {
482 type = argv[4];
483 }
484 code = atoi(code_str);
485
486 option = DHCPInfoGetOptionData(info, code);
487 if (option == NULL) {
488 exit(1);
489 }
490 len = CFDataGetLength(option);
491 if (type) {
492 printed = TRUE;
493 if (strcmp(type, "ip") == 0) {
494 int i = 0;
495 const void * ptr = CFDataGetBytePtr(option);
496
497 while (len >= 4) {
498 if (i == 0) {
499 printf(IP_FORMAT, IP_LIST(ptr));
500 }
501 else {
502 printf(" " IP_FORMAT, IP_LIST(ptr));
503 }
504 i++;
505 len -= 4;
506 ptr += 4;
507 }
508 printf("\n");
509 }
510 else if (strcmp(type, "string") == 0) {
511 printf("%.*s\n", (int)len, (char *)CFDataGetBytePtr(option));
512 }
513 else {
514 printed = FALSE;
515 }
516 }
517 if (!printed) {
518 print_data((void *)CFDataGetBytePtr(option), len);
519 }
520 if (serviceID)
521 CFRelease(serviceID);
522 CFRelease(info);
523 break;
524 }
525 case command_lease_e: {
526 CFDateRef start;
527
528 if (argv[2][0]) {
529 serviceID = CFStringCreateWithFormat(NULL, NULL,
530 CFSTR("%s"), argv[2]);
531 }
532
533 info = SCDynamicStoreCopyDHCPInfo(NULL, serviceID);
534 if (info == NULL) {
535 exit(1);
536 }
537 start = DHCPInfoGetLeaseStartTime(info);
538
539 if (start) {
540 CFDataRef option;
541 int32_t lease;
542
543 #define OPTION_LEASE_TIME 51
544 #define SERVER_ID 54
545 option = DHCPInfoGetOptionData(info, OPTION_LEASE_TIME);
546 if (option == NULL) {
547 fprintf(stderr, "what, no lease time?\n");
548 exit(1);
549 }
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");
555 }
556 else {
557 printf("Lease expires: ");
558 show_date(lease + CFDateGetAbsoluteTime(start));
559 }
560 option = DHCPInfoGetOptionData(info, SERVER_ID);
561 if (option) {
562 printf("Server IP: " IP_FORMAT "\n",
563 IP_LIST(CFDataGetBytePtr(option)));
564 }
565 }
566 else {
567 printf("no lease\n");
568 }
569 if (serviceID)
570 CFRelease(serviceID);
571 CFRelease(info);
572 break;
573 }
574 case command_getparams_e: {
575 app_id = CFStringCreateWithFormat(NULL, NULL,
576 CFSTR("%s"), argv[2]);
577 params = DHCPClientPreferencesCopyApplicationOptions(app_id, &count);
578 if (params) {
579 printf("%s params = {", argv[2]);
580 S_print_char_array(params, count);
581 printf("}\n");
582 free(params);
583 }
584 break;
585 }
586 case command_setparams_e: {
587 int count = 0;
588 UInt8 * options = NULL;
589
590 if (argc > 3) {
591 int i;
592
593 count = argc - 3;
594 options = malloc(count);
595 for (i = 0; i < count; i++) {
596 options[i] = atoi(argv[3 + i]);
597 }
598 }
599 app_id = CFStringCreateWithFormat(NULL, NULL,
600 CFSTR("%s"), argv[2]);
601 if (!DHCPClientPreferencesSetApplicationOptions(app_id, options, count) {
602 printf("operation failed\n");
603 }
604 if (options) {
605 free(options);
606 }
607 break;
608 }
609 default:
610 break;
611 }
612 exit(0);
613 return(0);
614 }
615 #endif // TEST_DHCPCLIENT_PREFERENCES
616