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