]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/DHCP.c
configd-293.4.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / DHCP.c
1 /*
2 * Copyright (c) 2001, 2003-2005 Apple Computer, 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 int count = 0;
46 int i;
47 int 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 int i;
81 int 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__ 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 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 boolean_t needs_close = FALSE;
244 CFDictionaryRef primary_dict = NULL;
245
246 if (store == NULL) {
247 needs_close = TRUE;
248 store = SCDynamicStoreCreate(NULL,
249 CFSTR("SCDynamicStoreCopyDHCPInfo"),
250 NULL, NULL);
251 if (store == NULL) {
252 goto done;
253 }
254 }
255
256 if (serviceID == NULL) {
257 /* get the primary service name */
258 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
259 kSCDynamicStoreDomainState,
260 kSCEntNetIPv4);
261 if (key) {
262 primary_dict = SCDynamicStoreCopyValue(store, key);
263 if (primary_dict) {
264 serviceID = CFDictionaryGetValue(primary_dict,
265 kSCDynamicStorePropNetPrimaryService);
266 }
267 CFRelease(key);
268 }
269 }
270 if (serviceID == NULL) {
271 goto done;
272 }
273 key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
274 kSCDynamicStoreDomainState,
275 serviceID,
276 kSCEntNetDHCP);
277 if (key) {
278 dhcp_dict = SCDynamicStoreCopyValue(store, key);
279 if (dhcp_dict != NULL
280 && isA_CFDictionary(dhcp_dict) == NULL) {
281 CFRelease(dhcp_dict);
282 dhcp_dict = NULL;
283 }
284 CFRelease(key);
285 }
286 done:
287 if (primary_dict) {
288 CFRelease(primary_dict);
289 }
290 if (needs_close == TRUE && store != NULL) {
291 CFRelease(store);
292 }
293 return (dhcp_dict);
294 }
295
296 CFDataRef
297 DHCPInfoGetOptionData(CFDictionaryRef dhcp_dict, UInt8 code)
298 {
299 CFDataRef data = NULL;
300 CFStringRef option_code_str = NULL;
301
302 option_code_str = CFStringCreateWithFormat(NULL, NULL,
303 CFSTR("Option_%d"), code);
304 if (option_code_str == NULL) {
305 goto done;
306 }
307
308 data = CFDictionaryGetValue(dhcp_dict, option_code_str);
309 data = isA_CFData(data);
310 done:
311 if (option_code_str)
312 CFRelease(option_code_str);
313 return (data);
314 }
315
316 CFDateRef
317 DHCPInfoGetLeaseStartTime(CFDictionaryRef dhcp_dict)
318 {
319 return (CFDictionaryGetValue(dhcp_dict, CFSTR("LeaseStartTime")));
320 }
321
322 #ifdef TEST_DHCPCLIENT_PREFERENCES
323 void
324 print_data(u_char * data_p, int n_bytes)
325 {
326 #define CHARS_PER_LINE 16
327 char line_buf[CHARS_PER_LINE + 1];
328 int line_pos;
329 int offset;
330
331 for (line_pos = 0, offset = 0; offset < n_bytes; offset++, data_p++) {
332 if (line_pos == 0)
333 printf("%04x ", offset);
334
335 line_buf[line_pos] = isprint(*data_p) ? *data_p : '.';
336 printf(" %02x", *data_p);
337 line_pos++;
338 if (line_pos == CHARS_PER_LINE) {
339 line_buf[CHARS_PER_LINE] = '\0';
340 printf(" %s\n", line_buf);
341 line_pos = 0;
342 }
343 else if (line_pos == (CHARS_PER_LINE / 2))
344 printf(" ");
345 }
346 if (line_pos) { /* need to finish up the line */
347 for (; line_pos < CHARS_PER_LINE; line_pos++) {
348 printf(" ");
349 line_buf[line_pos] = ' ';
350 }
351 line_buf[CHARS_PER_LINE] = '\0';
352 printf(" %s\n", line_buf);
353 }
354 }
355
356 #define CMDSTR_GETOPTION "getoption"
357 #define CMDSTR_LEASE "leaseinfo"
358 #define CMDSTR_GETPARAMS "getparams"
359 #define CMDSTR_SETPARAMS "setparams"
360
361 static __inline__ void
362 S_print_char_array(UInt8 * params, int n_params)
363 {
364 int i;
365
366 for (i = 0; i < n_params; i++) {
367 if (i == 0)
368 printf("%d", params[i]);
369 else
370 printf(", %d", params[i]);
371 }
372 return;
373 }
374
375 void
376 usage(char * prog)
377 {
378 printf("%s " CMDSTR_GETOPTION " <serviceID> <opt> [ <type> ]\n"
379 "%s " CMDSTR_LEASE " <serviceID>\n"
380 "%s " CMDSTR_GETPARAMS " <app_id>\n"
381 "%s " CMDSTR_SETPARAMS " <app_id> [ <opt> [ <opt> ] ... [ <opt> ] ] ]\n"
382 "where:\n"
383 " <serviceID> : service ID string | \"\"\n"
384 " <opt> : DHCP/BOOTP option code\n"
385 " (e.g. 1 == subnet mask, 3 == router, 6 = dns, 15 = domain)\n"
386 " <type> : type of option: string, ip\n"
387 " <app_id> : application id (e.g. com.apple.ntpd, com.thursby.Dave)\n",
388 prog, prog, prog, prog);
389 exit(0);
390 }
391
392 static void
393 dump_gregorian_date(CFGregorianDate d)
394 {
395 printf("%d/%d/%d %02d:%02d:%02d\n",
396 (int)d.year, d.month, d.day, d.hour, d.minute, (int)d.second);
397 return;
398 }
399
400 static void
401 show_date(CFAbsoluteTime t)
402 {
403 CFGregorianDate d;
404 static CFTimeZoneRef tz = NULL;
405
406 if (tz == NULL) {
407 tz = CFTimeZoneCopySystem();
408 }
409
410 d = CFAbsoluteTimeGetGregorianDate(t, tz);
411 dump_gregorian_date(d);
412 return;
413 }
414
415 #define IP_FORMAT "%d.%d.%d.%d"
416 #define IP_CH(ip, i) (((u_char *)(ip))[i])
417 #define IP_LIST(ip) IP_CH(ip,0),IP_CH(ip,1),IP_CH(ip,2),IP_CH(ip,3)
418
419 typedef enum {
420 command_none_e,
421 command_getoption_e,
422 command_lease_e,
423 command_setparams_e,
424 command_getparams_e,
425 } command_t;
426
427 int
428 main(int argc, char * argv[])
429 {
430 CFStringRef app_id;
431 command_t command = command_none_e;
432 char * command_str;
433 CFIndex count;
434 CFDictionaryRef info;
435 UInt8 * params;
436 CFStringRef serviceID = NULL;
437
438 command_str = argv[1];
439 if (argc < 2)
440 usage(argv[0]);
441 if (strcmp(command_str, CMDSTR_GETOPTION) == 0) {
442 if (argc < 4 || argc > 5) {
443 usage(argv[0]);
444 }
445 command = command_getoption_e;
446 }
447 else if (strcmp(command_str, CMDSTR_LEASE) == 0) {
448 if (argc != 3) {
449 usage(argv[0]);
450 }
451 command = command_lease_e;
452 }
453 else if (strcmp(command_str, CMDSTR_SETPARAMS) == 0) {
454 command = command_setparams_e;
455 if (argc < 3) {
456 usage(argv[0]);
457 }
458 }
459 else if (strcmp(command_str, CMDSTR_GETPARAMS) == 0) {
460 command = command_getparams_e;
461 if (argc != 3) {
462 usage(argv[0]);
463 }
464 }
465 else {
466 usage(argv[0]);
467 }
468
469 switch (command) {
470 case command_getoption_e: {
471 UInt8 code;
472 char * code_str;
473 CFDataRef option;
474 boolean_t printed = FALSE;
475 CFIndex len;
476 char * type = NULL;
477
478 if (argv[2][0]) {
479 serviceID = CFStringCreateWithFormat(NULL, NULL,
480 CFSTR("%s"), argv[2]);
481 }
482
483 info = SCDynamicStoreCopyDHCPInfo(NULL, serviceID);
484 if (info == NULL) {
485 exit(1);
486 }
487
488 code_str = argv[3];
489 if (argc > 4) {
490 type = argv[4];
491 }
492 code = atoi(code_str);
493
494 option = DHCPInfoGetOptionData(info, code);
495 if (option == NULL) {
496 exit(1);
497 }
498 len = CFDataGetLength(option);
499 if (type) {
500 printed = TRUE;
501 if (strcmp(type, "ip") == 0) {
502 int i = 0;
503 const void * ptr = CFDataGetBytePtr(option);
504
505 while (len >= 4) {
506 if (i == 0) {
507 printf(IP_FORMAT, IP_LIST(ptr));
508 }
509 else {
510 printf(" " IP_FORMAT, IP_LIST(ptr));
511 }
512 i++;
513 len -= 4;
514 ptr += 4;
515 }
516 printf("\n");
517 }
518 else if (strcmp(type, "string") == 0) {
519 printf("%.*s\n", (int)len, (char *)CFDataGetBytePtr(option));
520 }
521 else {
522 printed = FALSE;
523 }
524 }
525 if (printed == FALSE) {
526 print_data((void *)CFDataGetBytePtr(option), len);
527 }
528 if (serviceID)
529 CFRelease(serviceID);
530 CFRelease(info);
531 break;
532 }
533 case command_lease_e: {
534 CFDateRef start;
535
536 if (argv[2][0]) {
537 serviceID = CFStringCreateWithFormat(NULL, NULL,
538 CFSTR("%s"), argv[2]);
539 }
540
541 info = SCDynamicStoreCopyDHCPInfo(NULL, serviceID);
542 if (info == NULL) {
543 exit(1);
544 }
545 start = DHCPInfoGetLeaseStartTime(info);
546
547 if (start) {
548 CFDataRef option;
549 int32_t lease;
550
551 #define OPTION_LEASE_TIME 51
552 #define SERVER_ID 54
553 option = DHCPInfoGetOptionData(info, OPTION_LEASE_TIME);
554 if (option == NULL) {
555 fprintf(stderr, "what, no lease time?\n");
556 exit(1);
557 }
558 printf("Lease start: ");
559 show_date(CFDateGetAbsoluteTime(start));
560 lease = ntohl(*((int32_t *)CFDataGetBytePtr(option)));
561 if (lease == 0xffffffff) {
562 printf("Lease is infinite\n");
563 }
564 else {
565 printf("Lease expires: ");
566 show_date(lease + CFDateGetAbsoluteTime(start));
567 }
568 option = DHCPInfoGetOptionData(info, SERVER_ID);
569 if (option) {
570 printf("Server IP: " IP_FORMAT "\n",
571 IP_LIST(CFDataGetBytePtr(option)));
572 }
573 }
574 else {
575 printf("no lease\n");
576 }
577 if (serviceID)
578 CFRelease(serviceID);
579 CFRelease(info);
580 break;
581 }
582 case command_getparams_e: {
583 app_id = CFStringCreateWithFormat(NULL, NULL,
584 CFSTR("%s"), argv[2]);
585 params = DHCPClientPreferencesCopyApplicationOptions(app_id, &count);
586 if (params) {
587 printf("%s params = {", argv[2]);
588 S_print_char_array(params, count);
589 printf("}\n");
590 free(params);
591 }
592 break;
593 }
594 case command_setparams_e: {
595 int count = 0;
596 UInt8 * options = NULL;
597
598 if (argc > 3) {
599 int i;
600
601 count = argc - 3;
602 options = malloc(count);
603 if (options == NULL) {
604 fprintf(stderr, "malloc failed %s\n",
605 strerror(errno));
606 exit(1);
607 }
608 for (i = 0; i < count; i++) {
609 options[i] = atoi(argv[3 + i]);
610 }
611 }
612 app_id = CFStringCreateWithFormat(NULL, NULL,
613 CFSTR("%s"), argv[2]);
614 if (DHCPClientPreferencesSetApplicationOptions(app_id, options,
615 count) == FALSE) {
616 printf("operation failed\n");
617 }
618 if (options) {
619 free(options);
620 }
621 break;
622 }
623 default:
624 break;
625 }
626 exit(0);
627 return(0);
628 }
629 #endif TEST_DHCPCLIENT_PREFERENCES
630