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