]> git.saurik.com Git - apple/configd.git/blob - scutil.tproj/net_interface.c
configd-395.6.tar.gz
[apple/configd.git] / scutil.tproj / net_interface.c
1 /*
2 * Copyright (c) 2004-2011 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 /*
25 * Modification History
26 *
27 * August 5, 2004 Allan Nathanson <ajn@apple.com>
28 * - initial revision
29 */
30
31
32 #include "scutil.h"
33 #include "net.h"
34 #include "prefs.h"
35
36 #include <SystemConfiguration/LinkConfiguration.h>
37
38
39 #pragma mark -
40 #pragma mark Interface management
41
42
43 static CFArrayRef
44 _copy_interfaces()
45 {
46 CFMutableArrayRef interfaces;
47 CFArrayRef real_interfaces;
48
49 real_interfaces = _SCNetworkInterfaceCopyAllWithPreferences(prefs);
50 if (real_interfaces == NULL) {
51 SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
52 return NULL;
53 }
54
55 interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
56
57 // include real interfaces
58 CFArrayAppendArray(interfaces,
59 real_interfaces,
60 CFRangeMake(0, CFArrayGetCount(real_interfaces)));
61 CFRelease(real_interfaces);
62
63 // include pseudo interfaces
64 CFArrayAppendValue(interfaces, kSCNetworkInterfaceLoopback);
65 CFArrayAppendValue(interfaces, kSCNetworkInterfaceIPv4);
66
67 // include interfaces that we have created
68 if (new_interfaces != NULL) {
69 CFArrayAppendArray(interfaces,
70 new_interfaces,
71 CFRangeMake(0, CFArrayGetCount(new_interfaces)));
72 }
73
74 return (CFArrayRef)interfaces;
75 }
76
77
78 __private_extern__
79 SCNetworkInterfaceRef
80 _find_interface(int argc, char **argv, int *nArgs)
81 {
82 Boolean allowIndex = TRUE;
83 CFIndex i;
84 CFArrayRef myInterfaces = interfaces;
85 CFIndex n;
86 CFStringRef select_name = NULL;
87 SCNetworkInterfaceRef selected = NULL;
88
89 if (argc < 1) {
90 SCPrint(TRUE, stdout, CFSTR("no interface specified\n"));
91 return NULL;
92 }
93
94 if (nArgs != NULL) *nArgs = 1;
95
96 if (strcasecmp(argv[0], "$child") == 0) {
97 if (net_interface == NULL) {
98 SCPrint(TRUE, stdout, CFSTR("interface not selected\n"));
99 goto done;
100 }
101
102 selected = SCNetworkInterfaceGetInterface(net_interface);
103 if(selected == NULL) {
104 SCPrint(TRUE, stdout, CFSTR("no child interface\n"));
105 }
106
107 goto done;
108 } else if (strcasecmp(argv[0], "$service") == 0) {
109 if (net_service == NULL) {
110 SCPrint(TRUE, stdout, CFSTR("service not selected\n"));
111 goto done;
112 }
113
114 selected = SCNetworkServiceGetInterface(net_service);
115 if(selected == NULL) {
116 SCPrint(TRUE, stdout, CFSTR("no interface for service\n"));
117 }
118
119 goto done;
120 }
121
122 else if (strcasecmp(argv[0], "$bond") == 0) {
123 CFStringRef interfaceType;
124
125 if (net_interface == NULL) {
126 SCPrint(TRUE, stdout, CFSTR("interface not selected\n"));
127 goto done;
128 }
129
130 interfaceType = SCNetworkInterfaceGetInterfaceType(net_interface);
131 if (!CFEqual(interfaceType, kSCNetworkInterfaceTypeBond)) {
132 SCPrint(TRUE, stdout, CFSTR("interface not Bond\n"));
133 goto done;
134 }
135
136 if (argc < 2) {
137 SCPrint(TRUE, stdout, CFSTR("no member interface specified\n"));
138 return NULL;
139 }
140 argv++;
141 argc--;
142 if (nArgs != NULL) *nArgs += 1;
143
144 myInterfaces = SCBondInterfaceGetMemberInterfaces(net_interface);
145 if (myInterfaces == NULL) {
146 SCPrint(TRUE, stdout, CFSTR("no member interfaces\n"));
147 goto done;
148 }
149 allowIndex = FALSE;
150 }
151
152 else if (strcasecmp(argv[0], "$bridge") == 0) {
153 CFStringRef interfaceType;
154
155 if (net_interface == NULL) {
156 SCPrint(TRUE, stdout, CFSTR("interface not selected\n"));
157 goto done;
158 }
159
160 interfaceType = SCNetworkInterfaceGetInterfaceType(net_interface);
161 if (!CFEqual(interfaceType, kSCNetworkInterfaceTypeBridge)) {
162 SCPrint(TRUE, stdout, CFSTR("interface not Bridge\n"));
163 goto done;
164 }
165
166 if (argc < 2) {
167 SCPrint(TRUE, stdout, CFSTR("no member interface specified\n"));
168 return NULL;
169 }
170 argv++;
171 argc--;
172 if (nArgs != NULL) *nArgs += 1;
173
174 myInterfaces = SCBridgeInterfaceGetMemberInterfaces(net_interface);
175 if (myInterfaces == NULL) {
176 SCPrint(TRUE, stdout, CFSTR("no member interfaces\n"));
177 goto done;
178 }
179 allowIndex = FALSE;
180 }
181
182 else if (strcasecmp(argv[0], "$vlan") == 0) {
183 CFStringRef interfaceType;
184
185 if (net_interface == NULL) {
186 SCPrint(TRUE, stdout, CFSTR("interface not selected\n"));
187 goto done;
188 }
189
190 interfaceType = SCNetworkInterfaceGetInterfaceType(net_interface);
191 if (!CFEqual(interfaceType, kSCNetworkInterfaceTypeVLAN)) {
192 SCPrint(TRUE, stdout, CFSTR("interface not VLAN\n"));
193 goto done;
194 }
195
196 selected = SCVLANInterfaceGetPhysicalInterface(net_interface);
197 if(selected == NULL) {
198 SCPrint(TRUE, stdout, CFSTR("no physical interface\n"));
199 }
200
201 goto done;
202 }
203
204 if ((myInterfaces == NULL) && (interfaces == NULL)) {
205 interfaces = _copy_interfaces();
206 if (interfaces == NULL) {
207 return NULL;
208 }
209 myInterfaces = interfaces;
210 allowIndex = FALSE;
211 }
212
213 // try to select the interface by its display name
214
215 select_name = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
216
217 n = (myInterfaces != NULL) ? CFArrayGetCount(myInterfaces) : 0;
218 for (i = 0; i < n; i++) {
219 SCNetworkInterfaceRef interface;
220 CFStringRef interfaceName;
221
222 interface = CFArrayGetValueAtIndex(myInterfaces, i);
223 interfaceName = SCNetworkInterfaceGetLocalizedDisplayName(interface);
224 if ((interfaceName != NULL) && CFEqual(select_name, interfaceName)) {
225 if (selected == NULL) {
226 selected = interface;
227 } else {
228 // if multiple interfaces match
229 selected = NULL;
230 SCPrint(TRUE, stdout, CFSTR("multiple interfaces match\n"));
231 goto done;
232 }
233 }
234 }
235
236 if (selected != NULL) {
237 goto done;
238 }
239
240 // try to select the interface by its BSD name
241
242 for (i = 0; i < n; i++) {
243 SCNetworkInterfaceRef interface;
244 CFStringRef bsd_name = NULL;
245
246 interface = CFArrayGetValueAtIndex(myInterfaces, i);
247 while ((interface != NULL) && (bsd_name == NULL)) {
248 bsd_name = SCNetworkInterfaceGetBSDName(interface);
249 if (bsd_name == NULL) {
250 interface = SCNetworkInterfaceGetInterface(interface);
251 }
252 }
253
254 if ((bsd_name != NULL) && CFEqual(select_name, bsd_name)) {
255 if (selected == NULL) {
256 selected = interface;
257 } else {
258 // if multiple interfaces match
259 selected = NULL;
260 SCPrint(TRUE, stdout, CFSTR("multiple interfaces match\n"));
261 goto done;
262 }
263 }
264 }
265
266 if (selected != NULL) {
267 goto done;
268 }
269
270 // try to select the interface by its interface type
271
272 for (i = 0; i < n; i++) {
273 SCNetworkInterfaceRef interface;
274 CFStringRef interfaceType;
275
276 interface = CFArrayGetValueAtIndex(myInterfaces, i);
277 interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
278 if (CFEqual(select_name, interfaceType)) {
279 if (selected == NULL) {
280 selected = interface;
281 } else {
282 // if multiple interfaces match
283 selected = NULL;
284 SCPrint(TRUE, stdout, CFSTR("multiple interfaces match\n"));
285 goto done;
286 }
287 }
288 }
289
290 if (selected != NULL) {
291 goto done;
292 }
293
294 if (allowIndex) {
295 char *end;
296 char *str = argv[0];
297 long val;
298
299 // try to select the interface by its index
300
301 errno = 0;
302 val = strtol(str, &end, 10);
303 if ((*str != '\0') &&
304 ((*end == '\0') || (*end == '.')) &&
305 (errno == 0)) {
306 if ((val > 0) && (val <= n)) {
307 selected = CFArrayGetValueAtIndex(myInterfaces, val - 1);
308
309 if (*end == '.') {
310 str = end + 1;
311 val = strtol(str, &end, 10);
312 if ((*str != '\0') && (*end == '\0') && (errno == 0)) {
313 while (val-- > 0) {
314 selected = SCNetworkInterfaceGetInterface(selected);
315 if (selected == NULL) {
316 break;
317 }
318 }
319 }
320 }
321 }
322 }
323 }
324
325 if (selected != NULL) {
326 goto done;
327 }
328
329 SCPrint(TRUE, stdout, CFSTR("no match\n"));
330
331 done :
332
333 if (select_name != NULL) CFRelease(select_name);
334 return selected;
335 }
336
337
338 /* -------------------- */
339
340
341 __private_extern__
342 void
343 create_interface(int argc, char **argv)
344 {
345 SCNetworkInterfaceRef interface;
346 CFStringRef interfaceName;
347 CFStringRef interfaceType;
348 SCNetworkInterfaceRef new_interface;
349
350 if (argc < 1) {
351 SCPrint(TRUE, stdout, CFSTR("what interface type?\n"));
352 return;
353 }
354
355 interfaceType = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
356 argv++;
357 argc--;
358
359 if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBond)) {
360 SCPrint(TRUE, stdout, CFSTR("bond creation not yet supported\n"));
361 goto done;
362 }
363 if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBridge)) {
364 SCPrint(TRUE, stdout, CFSTR("bridge creation not yet supported\n"));
365 goto done;
366 }
367 if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVLAN)) {
368 SCPrint(TRUE, stdout, CFSTR("vlan creation not yet supported\n"));
369 goto done;
370 }
371
372 if (argc < 1) {
373 if (net_interface == NULL) {
374 SCPrint(TRUE, stdout, CFSTR("no network interface selected\n"));
375 goto done;
376 }
377
378 interface = net_interface;
379 } else {
380 interface = _find_interface(argc, argv, NULL);
381 }
382
383 if (interface == NULL) {
384 goto done;
385 }
386
387 new_interface = SCNetworkInterfaceCreateWithInterface(interface, interfaceType);
388 if (new_interface == NULL) {
389 SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
390 goto done;
391 }
392
393 if (new_interfaces == NULL) {
394 new_interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
395 }
396 CFArrayAppendValue(new_interfaces, new_interface);
397
398 if (net_interface != NULL) CFRelease(net_interface);
399 net_interface = new_interface;
400
401 interfaceName = SCNetworkInterfaceGetLocalizedDisplayName(net_interface);
402 if (interfaceName == NULL) {
403 interfaceName = SCNetworkInterfaceGetBSDName(net_interface);
404 }
405 if (interfaceName == NULL) {
406 interfaceName = SCNetworkInterfaceGetInterfaceType(net_interface);
407 }
408 SCPrint(TRUE, stdout, CFSTR("interface \"%@\" created and selected\n"), interfaceName);
409
410 done :
411
412 CFRelease(interfaceType);
413 return;
414 }
415
416
417 /* -------------------- */
418
419
420 __private_extern__
421 void
422 select_interface(int argc, char **argv)
423 {
424 SCNetworkInterfaceRef interface;
425
426 interface = _find_interface(argc, argv, NULL);
427 if (interface != NULL) {
428 CFStringRef interfaceName;
429
430 if (net_interface != NULL) CFRelease(net_interface);
431 net_interface = CFRetain(interface);
432
433 interfaceName = SCNetworkInterfaceGetLocalizedDisplayName(interface);
434 if (interfaceName == NULL) {
435 interfaceName = SCNetworkInterfaceGetBSDName(interface);
436 }
437 if (interfaceName == NULL) {
438 interfaceName = SCNetworkInterfaceGetInterfaceType(interface);
439 }
440
441 SCPrint(TRUE, stdout, CFSTR("interface \"%@\" selected\n"), interfaceName);
442 }
443
444 return;
445 }
446
447
448 /* -------------------- */
449
450
451 __private_extern__
452 void
453 _show_interface(SCNetworkInterfaceRef interface, CFStringRef prefix, Boolean showChild)
454 {
455 CFDictionaryRef configuration;
456 CFStringRef if_bsd_name;
457 CFStringRef if_localized_name;
458 CFStringRef if_mac_address;
459 CFStringRef if_type;
460 CFArrayRef supported;
461
462 if_localized_name = SCNetworkInterfaceGetLocalizedDisplayName(interface);
463 if (if_localized_name != NULL) {
464 SCPrint(TRUE, stdout, CFSTR("%@ name = %@\n"), prefix, if_localized_name);
465 }
466
467 if_bsd_name = SCNetworkInterfaceGetBSDName(interface);
468 if (if_bsd_name != NULL) {
469 SCPrint(TRUE, stdout, CFSTR("%@ interface name = %@\n"), prefix, if_bsd_name);
470 }
471
472 if_type = SCNetworkInterfaceGetInterfaceType(interface);
473 SCPrint(TRUE, stdout, CFSTR("%@ type = %@\n"), prefix, if_type);
474
475 if_mac_address = SCNetworkInterfaceGetHardwareAddressString(interface);
476 if (if_mac_address != NULL) {
477 SCPrint(TRUE, stdout, CFSTR("%@ address = %@\n"), prefix, if_mac_address);
478 }
479
480 configuration = SCNetworkInterfaceGetConfiguration(interface);
481 if ((configuration != NULL) &&
482 CFDictionaryContainsKey(configuration, kSCResvInactive)) {
483 configuration = NULL;
484 }
485
486 if (if_bsd_name != NULL) {
487 CFArrayRef available;
488 CFDictionaryRef active;
489 CFDictionaryRef cap_current;
490 int mtu_cur;
491 int mtu_min;
492 int mtu_max;
493
494 cap_current = SCNetworkInterfaceCopyCapability(interface, NULL);
495 if (cap_current != NULL) {
496 CFIndex i;
497 CFArrayRef cap_names;
498 CFMutableArrayRef cap_sorted;
499 const void **keys;
500 CFIndex n;
501
502 n = CFDictionaryGetCount(cap_current);
503 keys = CFAllocatorAllocate(NULL, n * sizeof(CFStringRef), 0);
504 CFDictionaryGetKeysAndValues(cap_current, keys, NULL);
505 cap_names = CFArrayCreate(NULL, keys, n, &kCFTypeArrayCallBacks);
506 CFAllocatorDeallocate(NULL, keys);
507
508 cap_sorted = CFArrayCreateMutableCopy(NULL, 0, cap_names);
509 CFRelease(cap_names);
510
511 CFArraySortValues(cap_sorted, CFRangeMake(0, n), (CFComparatorFunction)CFStringCompare, NULL);
512
513 SCPrint(TRUE, stdout, CFSTR("%@ capabilities = "), prefix);
514 for (i = 0; i < n; i++) {
515 CFStringRef cap_name;
516 int cap_val;
517 CFNumberRef val = NULL;
518
519 cap_name = CFArrayGetValueAtIndex(cap_sorted, i);
520 if (configuration != NULL) {
521 val = CFDictionaryGetValue(configuration, cap_name);
522 }
523 if (!isA_CFNumber(val)) {
524 val = CFDictionaryGetValue(cap_current, cap_name);
525 }
526
527 SCPrint(TRUE, stdout, CFSTR("%s%@%c"),
528 (i == 0) ? "" : ",",
529 cap_name,
530 (CFNumberGetValue(val, kCFNumberIntType, &cap_val) &&
531 (cap_val != 0)) ? '+' : '-');
532 }
533 SCPrint(TRUE, stdout, CFSTR("\n"));
534
535 CFRelease(cap_sorted);
536 CFRelease(cap_current);
537 }
538
539 if (SCNetworkInterfaceCopyMTU(interface, &mtu_cur, &mtu_min, &mtu_max)) {
540 char isCurrent = '*';
541
542 if (configuration != NULL) {
543 int mtu_req;
544 CFNumberRef num;
545
546 num = CFDictionaryGetValue(configuration, kSCPropNetEthernetMTU);
547 if (isA_CFNumber(num)) {
548 CFNumberGetValue(num, kCFNumberIntType, &mtu_req);
549 if (mtu_cur != mtu_req) {
550 mtu_cur = mtu_req;
551 isCurrent = ' ';
552 }
553 }
554 }
555
556 SCPrint(TRUE, stdout, CFSTR("%@ mtu %c = %d (%d < n < %d)\n"),
557 prefix,
558 isCurrent,
559 mtu_cur,
560 mtu_min,
561 mtu_max);
562 }
563
564 if (SCNetworkInterfaceCopyMediaOptions(interface, NULL, &active, &available, TRUE)) {
565 char isCurrent = ' ';
566 CFArrayRef options = NULL;
567 CFArrayRef options_req = NULL;
568 CFStringRef subtype = NULL;
569 CFStringRef subtype_req = NULL;
570
571 if (configuration != NULL) {
572 subtype_req = CFDictionaryGetValue(configuration, kSCPropNetEthernetMediaSubType);
573 options_req = CFDictionaryGetValue(configuration, kSCPropNetEthernetMediaOptions);
574 }
575
576 if (subtype_req == NULL) {
577 subtype_req = CFSTR("autoselect");
578 }
579
580 if (active != NULL) {
581 subtype = CFDictionaryGetValue(active, kSCPropNetEthernetMediaSubType);
582 options = CFDictionaryGetValue(active, kSCPropNetEthernetMediaOptions);
583 }
584
585 if (subtype != NULL) {
586 if (((subtype_req != NULL) &&
587 CFEqual(subtype, subtype_req)) &&
588 ((options == options_req) ||
589 ((options != NULL) &&
590 (options_req != NULL) &&
591 CFEqual(options, options_req)))
592 ) {
593 isCurrent = '*';
594 } else if ((subtype_req == NULL) ||
595 ((subtype_req != NULL) &&
596 CFEqual(subtype_req, CFSTR("autoselect")))) {
597 // if requested subtype not specified or "autoselect"
598 isCurrent = '*';
599 }
600 }
601
602 if (subtype_req != NULL) {
603 SCPrint(TRUE, stdout, CFSTR("%@ media %c = %@"),
604 prefix,
605 isCurrent,
606 subtype_req);
607
608 if ((options_req != NULL) &&
609 (CFArrayGetCount(options_req) > 0)) {
610 CFStringRef options_str;
611
612 options_str = CFStringCreateByCombiningStrings(NULL, options_req, CFSTR(","));
613 SCPrint(TRUE, stdout, CFSTR(" <%@>"), options_str);
614 CFRelease(options_str);
615 }
616
617 SCPrint(TRUE, stdout, CFSTR("\n"));
618 }
619
620 SCPrint(TRUE, stdout, CFSTR("\n"));
621
622 if (available != NULL) {
623 CFIndex i;
624 CFIndex n_subtypes;
625 CFArrayRef subtypes;
626
627 subtypes = SCNetworkInterfaceCopyMediaSubTypes(available);
628 n_subtypes = (subtypes != NULL) ? CFArrayGetCount(subtypes) : 0;
629 for (i = 0; i < n_subtypes; i++) {
630 CFIndex j;
631 CFIndex n_subtype_options;
632 CFStringRef subtype;
633 CFArrayRef subtype_options;
634
635 subtype = CFArrayGetValueAtIndex(subtypes, i);
636 subtype_options = SCNetworkInterfaceCopyMediaSubTypeOptions(available, subtype);
637 n_subtype_options = (subtype_options != NULL) ? CFArrayGetCount(subtype_options) : 0;
638 for (j = 0; j < n_subtype_options; j++) {
639 char isCurrent = ' ';
640 CFArrayRef options;
641
642 options = CFArrayGetValueAtIndex(subtype_options, j);
643
644 if (((subtype_req != NULL) &&
645 CFEqual(subtype, subtype_req)) &&
646 ((options == options_req) ||
647 ((options != NULL) &&
648 (options_req != NULL) &&
649 CFEqual(options, options_req)))
650 ) {
651 isCurrent = '*';
652 }
653
654 SCPrint(TRUE, stdout, CFSTR("%@ %s %c = %@"),
655 prefix,
656 ((i == 0) && (j == 0)) ? "supported media" : " ",
657 isCurrent,
658 subtype);
659
660 if ((options != NULL) &&
661 (CFArrayGetCount(options) > 0)) {
662 CFStringRef options_str;
663
664 options_str = CFStringCreateByCombiningStrings(NULL, options, CFSTR(","));
665 SCPrint(TRUE, stdout, CFSTR(" <%@>"), options_str);
666 CFRelease(options_str);
667 }
668
669 SCPrint(TRUE, stdout, CFSTR("\n"));
670 }
671 if (subtype_options != NULL) CFRelease(subtype_options);
672 }
673 if (subtypes != NULL) CFRelease(subtypes);
674 }
675 } else {
676 SCPrint(TRUE, stdout, CFSTR("\n"));
677 }
678 }
679
680 supported = SCNetworkInterfaceGetSupportedInterfaceTypes(interface);
681 SCPrint(TRUE, stdout, CFSTR("%@ supported interfaces = "), prefix);
682 if (supported != NULL) {
683 CFIndex i;
684 CFIndex n = CFArrayGetCount(supported);
685
686 for (i = 0; i < n; i++) {
687 SCPrint(TRUE, stdout, CFSTR("%s%@"),
688 (i == 0) ? "" : ", ",
689 CFArrayGetValueAtIndex(supported, i));
690 }
691 }
692 SCPrint(TRUE, stdout, CFSTR("\n"));
693
694 supported = SCNetworkInterfaceGetSupportedProtocolTypes(interface);
695 SCPrint(TRUE, stdout, CFSTR("%@ supported protocols = "), prefix);
696 if (supported != NULL) {
697 CFIndex i;
698 CFIndex n = CFArrayGetCount(supported);
699
700 for (i = 0; i < n; i++) {
701 SCPrint(TRUE, stdout, CFSTR("%s%@"),
702 (i == 0) ? "" : ", ",
703 CFArrayGetValueAtIndex(supported, i));
704 }
705 }
706 SCPrint(TRUE, stdout, CFSTR("\n"));
707
708 if (configuration != NULL) {
709 CFMutableDictionaryRef effective;
710
711 effective = CFDictionaryCreateMutableCopy(NULL, 0, configuration);
712
713 // remove known (and already reported) interface configuration keys
714 if (CFDictionaryContainsKey(effective, kSCResvInactive)) {
715 CFDictionaryRemoveAllValues(effective);
716 }
717 CFDictionaryRemoveValue(effective, kSCPropNetEthernetMTU);
718 CFDictionaryRemoveValue(effective, kSCPropNetEthernetMediaSubType);
719 CFDictionaryRemoveValue(effective, kSCPropNetEthernetMediaOptions);
720
721 if (CFDictionaryGetCount(effective) > 0) {
722 SCPrint(TRUE, stdout, CFSTR("\n%@ per-interface configuration\n"), prefix);
723 _show_entity(effective, prefix);
724 }
725
726 CFRelease(effective);
727 }
728
729 if (CFEqual(if_type, kSCNetworkInterfaceTypePPP)) {
730 SCNetworkInterfaceRef childInterface;
731
732 childInterface = SCNetworkInterfaceGetInterface(interface);
733 if (childInterface != NULL) {
734 CFStringRef childInterfaceType;
735
736 childInterfaceType = SCNetworkInterfaceGetInterfaceType(childInterface);
737 if (CFEqual(childInterfaceType, kSCNetworkInterfaceTypeL2TP)) {
738 CFDictionaryRef ipsec_configuration;
739
740 ipsec_configuration = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetIPSec);
741 if (isA_CFDictionary(ipsec_configuration) &&
742 (CFDictionaryGetCount(ipsec_configuration) > 0)) {
743 SCPrint(TRUE, stdout, CFSTR("\n%@ per-interface IPSec configuration\n"), prefix);
744 _show_entity(ipsec_configuration, prefix);
745 }
746 }
747 }
748 }
749
750 if (_sc_debug) {
751 SCPrint(TRUE, stdout, CFSTR("\n%@\n"), interface);
752 }
753
754 interface = SCNetworkInterfaceGetInterface(interface);
755 if (interface != NULL) {
756 CFStringRef newPrefix;
757
758 newPrefix = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@ "), prefix);
759 SCPrint(TRUE, stdout, CFSTR("\n%@child interface\n"), newPrefix);
760 _show_interface(interface, newPrefix, showChild);
761 CFRelease(newPrefix);
762 }
763
764 return;
765 }
766
767
768 /* -------------------- */
769
770
771 static Boolean
772 validateMediaOptions(SCNetworkInterfaceRef interface, CFMutableDictionaryRef newConfiguration)
773 {
774 Boolean ok = TRUE;
775 CFNumberRef mtu;
776 CFArrayRef options;
777 CFStringRef subtype;
778
779 mtu = CFDictionaryGetValue(newConfiguration, kSCPropNetEthernetMTU);
780 if (isA_CFNumber(mtu)) {
781 int mtu_max;
782 int mtu_min;
783 int mtu_val;
784
785 if (!SCNetworkInterfaceCopyMTU(interface, NULL, &mtu_min, &mtu_max)) {
786 SCPrint(TRUE, stdout, CFSTR("cannot set MTU\n"));
787 return FALSE;
788 }
789
790 if (!CFNumberGetValue(mtu, kCFNumberIntType, &mtu_val) ||
791 (mtu_val < mtu_min) ||
792 (mtu_val > mtu_max)) {
793 SCPrint(TRUE, stdout, CFSTR("mtu out of range\n"));
794 return FALSE;
795 }
796 }
797
798 subtype = CFDictionaryGetValue(newConfiguration, kSCPropNetEthernetMediaSubType);
799 options = CFDictionaryGetValue(newConfiguration, kSCPropNetEthernetMediaOptions);
800
801 if (subtype != NULL) {
802 CFArrayRef available = NULL;
803 CFArrayRef config_options = options;
804 CFArrayRef subtypes = NULL;
805 CFArrayRef subtype_options = NULL;
806
807 ok = FALSE;
808
809 if (options == NULL) {
810 config_options = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
811 }
812
813 if (!SCNetworkInterfaceCopyMediaOptions(interface, NULL, NULL, &available, FALSE)) {
814 SCPrint(TRUE, stdout, CFSTR("media type / options not available\n"));
815 goto checked;
816 }
817
818 if (available == NULL) {
819 goto checked;
820 }
821
822 subtypes = SCNetworkInterfaceCopyMediaSubTypes(available);
823 if ((subtypes == NULL) ||
824 !CFArrayContainsValue(subtypes,
825 CFRangeMake(0, CFArrayGetCount(subtypes)),
826 subtype)) {
827 SCPrint(TRUE, stdout, CFSTR("media type not valid\n"));
828 goto checked;
829 }
830
831 subtype_options = SCNetworkInterfaceCopyMediaSubTypeOptions(available, subtype);
832 if ((subtype_options == NULL) ||
833 !CFArrayContainsValue(subtype_options,
834 CFRangeMake(0, CFArrayGetCount(subtype_options)),
835 config_options)) {
836 SCPrint(TRUE, stdout, CFSTR("media options not valid for \"%@\"\n"), subtype);
837 goto checked;
838 }
839
840 if (options == NULL) {
841 CFDictionarySetValue(newConfiguration, kSCPropNetEthernetMediaOptions, config_options);
842 }
843
844 ok = TRUE;
845
846 checked :
847
848 if (available != NULL) CFRelease(available);
849 if (subtypes != NULL) CFRelease(subtypes);
850 if (subtype_options != NULL) CFRelease(subtype_options);
851 if (options == NULL) CFRelease(config_options);
852 } else {
853 if (options != NULL) {
854 SCPrint(TRUE, stdout, CFSTR("media type and options must both be specified\n"));
855 return FALSE;
856 }
857 }
858
859 return ok;
860 }
861
862
863 /* -------------------- */
864
865
866 __private_extern__
867 void
868 show_interfaces(int argc, char **argv)
869 {
870 CFIndex i;
871 CFIndex n;
872
873 if (interfaces != NULL) CFRelease(interfaces);
874 interfaces = _copy_interfaces();
875 if (interfaces == NULL) {
876 return;
877 }
878
879 n = CFArrayGetCount(interfaces);
880 for (i = 0; i < n; i++) {
881 CFIndex childIndex = 0;
882 SCNetworkInterfaceRef interface;
883
884 interface = CFArrayGetValueAtIndex(interfaces, i);
885 do {
886 CFStringRef interfaceName;
887 char isSelected;
888
889 interfaceName = SCNetworkInterfaceGetLocalizedDisplayName(interface);
890 if (interfaceName == NULL) {
891 interfaceName = SCNetworkInterfaceGetBSDName(interface);
892 }
893 if (interfaceName == NULL) {
894 interfaceName = SCNetworkInterfaceGetInterfaceType(interface);
895 }
896
897 isSelected = ' ';
898 if ((net_interface != NULL) && CFEqual(interface, net_interface)) {
899 isSelected = '>';
900 }
901
902 if (childIndex == 0) {
903 SCPrint(TRUE, stdout, CFSTR("%c%2d: %@\n"),
904 isSelected,
905 i + 1,
906 interfaceName);
907 } else {
908 SCPrint(TRUE, stdout, CFSTR("%c%2d.%d: %@\n"),
909 isSelected,
910 i + 1,
911 childIndex,
912 interfaceName);
913 }
914
915 interface = SCNetworkInterfaceGetInterface(interface);
916 childIndex++;
917 } while (interface != NULL);
918 }
919
920 return;
921 }
922
923
924 /* -------------------- */
925
926
927 static void
928 _replaceOne(const void *key, const void *value, void *context)
929 {
930 CFMutableDictionaryRef newConfiguration = (CFMutableDictionaryRef)context;
931
932 CFDictionarySetValue(newConfiguration, key, value);
933 return;
934 }
935
936
937 static void
938 updateInterfaceConfiguration(CFMutableDictionaryRef newConfiguration)
939 {
940 CFDictionaryRef configuration;
941
942 CFDictionaryRemoveAllValues(newConfiguration);
943
944 configuration = SCNetworkInterfaceGetConfiguration(net_interface);
945 if (configuration != NULL) {
946 CFDictionaryApplyFunction(configuration, _replaceOne, (void *)newConfiguration);
947 }
948
949 return;
950 }
951
952
953 #pragma mark -
954 #pragma mark Bond options
955
956
957 static options bondOptions[] = {
958 { "mtu" , NULL, isNumber , &kSCPropNetEthernetMTU , NULL, NULL },
959 // xxx { "+device" , ... },
960 // xxx { "-device" , ... },
961
962 { "?" , NULL , isHelp , NULL , NULL,
963 "\nBond configuration commands\n\n"
964 " set interface [mtu n] [media type] [mediaopts opts]\n"
965 }
966 };
967 #define N_BOND_OPTIONS (sizeof(bondOptions) / sizeof(bondOptions[0]))
968
969
970 static Boolean
971 set_interface_bond(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
972 {
973 CFStringRef interfaceName;
974 Boolean ok;
975
976 interfaceName = SCNetworkInterfaceGetBSDName(net_interface);
977 if (interfaceName == NULL) {
978 SCPrint(TRUE, stdout, CFSTR("no BSD interface\n"));
979 return FALSE;
980 }
981
982 ok = _process_options(bondOptions, N_BOND_OPTIONS, argc, argv, newConfiguration);
983 if (ok) {
984 // validate configuration
985 if (!validateMediaOptions(net_interface, newConfiguration)) {
986 return FALSE;
987 }
988 }
989
990 return ok;
991 }
992
993
994 #pragma mark -
995 #pragma mark Bridge options
996
997
998 static options bridgeOptions[] = {
999 { "mtu" , NULL, isNumber , &kSCPropNetEthernetMTU , NULL, NULL },
1000 // xxx { "+device" , ... },
1001 // xxx { "-device" , ... },
1002
1003 { "?" , NULL , isHelp , NULL , NULL,
1004 "\nBridge configuration commands\n\n"
1005 " set interface [mtu n] [media type] [mediaopts opts]\n"
1006 }
1007 };
1008 #define N_BRIDGE_OPTIONS (sizeof(bridgeOptions) / sizeof(bridgeOptions[0]))
1009
1010
1011 static Boolean
1012 set_interface_bridge(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1013 {
1014 CFStringRef interfaceName;
1015 Boolean ok;
1016
1017 interfaceName = SCNetworkInterfaceGetBSDName(net_interface);
1018 if (interfaceName == NULL) {
1019 SCPrint(TRUE, stdout, CFSTR("no BSD interface\n"));
1020 return FALSE;
1021 }
1022
1023 ok = _process_options(bridgeOptions, N_BRIDGE_OPTIONS, argc, argv, newConfiguration);
1024 if (ok) {
1025 // validate configuration
1026 if (!validateMediaOptions(net_interface, newConfiguration)) {
1027 return FALSE;
1028 }
1029 }
1030
1031 return ok;
1032 }
1033
1034
1035 #pragma mark -
1036 #pragma mark AirPort options
1037
1038
1039 static options airportOptions[] = {
1040 { "mtu" , NULL, isNumber , &kSCPropNetEthernetMTU , NULL, NULL },
1041 { "media" , NULL, isString , &kSCPropNetEthernetMediaSubType, NULL, NULL },
1042 { "mediaopt" , NULL, isStringArray, &kSCPropNetEthernetMediaOptions, NULL, NULL },
1043
1044 { "?" , NULL , isHelp , NULL , NULL,
1045 "\nAirPort configuration commands\n\n"
1046 " set interface [mtu n] [media type] [mediaopts opts]\n"
1047 }
1048 };
1049 #define N_AIRPORT_OPTIONS (sizeof(airportOptions) / sizeof(airportOptions[0]))
1050
1051
1052 static Boolean
1053 set_interface_airport(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1054 {
1055 CFStringRef interfaceName;
1056 Boolean ok;
1057
1058 interfaceName = SCNetworkInterfaceGetBSDName(net_interface);
1059 if (interfaceName == NULL) {
1060 SCPrint(TRUE, stdout, CFSTR("no BSD interface\n"));
1061 return FALSE;
1062 }
1063
1064 ok = _process_options(airportOptions, N_AIRPORT_OPTIONS, argc, argv, newConfiguration);
1065 if (ok) {
1066 // validate configuration
1067 if (!validateMediaOptions(net_interface, newConfiguration)) {
1068 return FALSE;
1069 }
1070 }
1071
1072 return ok;
1073 }
1074
1075
1076 #pragma mark -
1077 #pragma mark Ethernet options
1078
1079
1080 static int
1081 __doCapability(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1082 {
1083 Boolean ok = FALSE;
1084
1085 if (argc < 1) {
1086 SCPrint(TRUE, stdout,
1087 CFSTR("%s not specified\n"),
1088 description != NULL ? description : "enable/disable");
1089 return -1;
1090 }
1091
1092 if (strlen(argv[0]) == 0) {
1093 ok = SCNetworkInterfaceSetCapability(net_interface, key, NULL);
1094 } else if ((strcasecmp(argv[0], "disable") == 0) ||
1095 (strcasecmp(argv[0], "no" ) == 0) ||
1096 (strcasecmp(argv[0], "off" ) == 0) ||
1097 (strcasecmp(argv[0], "0" ) == 0)) {
1098 ok = SCNetworkInterfaceSetCapability(net_interface, key, CFNumberRef_0);
1099 } else if ((strcasecmp(argv[0], "enable") == 0) ||
1100 (strcasecmp(argv[0], "yes" ) == 0) ||
1101 (strcasecmp(argv[0], "on" ) == 0) ||
1102 (strcasecmp(argv[0], "1" ) == 0)) {
1103 ok = SCNetworkInterfaceSetCapability(net_interface, key, CFNumberRef_1);
1104 } else {
1105 SCPrint(TRUE, stdout, CFSTR("invalid value\n"));
1106 return -1;
1107 }
1108
1109 if (ok) {
1110 updateInterfaceConfiguration(newConfiguration);
1111 } else {
1112 SCPrint(TRUE, stdout,
1113 CFSTR("%@ not updated: %s\n"),
1114 key,
1115 SCErrorString(SCError()));
1116 return -1;
1117 }
1118
1119 return 1;
1120 }
1121
1122
1123 static options ethernetOptions[] = {
1124 { "mtu" , NULL, isNumber , &kSCPropNetEthernetMTU , NULL, NULL },
1125 { "media" , NULL, isString , &kSCPropNetEthernetMediaSubType, NULL, NULL },
1126 { "mediaopt" , NULL, isStringArray, &kSCPropNetEthernetMediaOptions, NULL, NULL },
1127
1128 { "av" , NULL, isOther , &kSCPropNetEthernetCapabilityAV , __doCapability, NULL },
1129 { "lro" , NULL, isOther , &kSCPropNetEthernetCapabilityLRO , __doCapability, NULL },
1130 { "rxcsum" , NULL, isOther , &kSCPropNetEthernetCapabilityRXCSUM, __doCapability, NULL },
1131 { "tso" , NULL, isOther , &kSCPropNetEthernetCapabilityTSO , __doCapability, NULL },
1132 { "txcsum" , NULL, isOther , &kSCPropNetEthernetCapabilityTXCSUM, __doCapability, NULL },
1133
1134 { "?" , NULL , isHelp , NULL , NULL,
1135 "\nEthernet configuration commands\n\n"
1136 " set interface [mtu n] [media type] [mediaopts opts]\n"
1137 }
1138 };
1139 #define N_ETHERNET_OPTIONS (sizeof(ethernetOptions) / sizeof(ethernetOptions[0]))
1140
1141
1142 static Boolean
1143 set_interface_ethernet(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1144 {
1145 CFStringRef interfaceName;
1146 Boolean ok;
1147
1148 interfaceName = SCNetworkInterfaceGetBSDName(net_interface);
1149 if (interfaceName == NULL) {
1150 SCPrint(TRUE, stdout, CFSTR("no BSD interface\n"));
1151 return FALSE;
1152 }
1153
1154 ok = _process_options(ethernetOptions, N_ETHERNET_OPTIONS, argc, argv, newConfiguration);
1155 if (ok) {
1156 // validate configuration
1157 if (!validateMediaOptions(net_interface, newConfiguration)) {
1158 return FALSE;
1159 }
1160 }
1161
1162 return ok;
1163 }
1164
1165
1166 #pragma mark -
1167 #pragma mark IPSec options
1168
1169
1170 static int
1171 __doIPSecSharedSecret(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1172 {
1173 CFStringRef encryptionType;
1174
1175 if (argc < 1) {
1176 SCPrint(TRUE, stdout, CFSTR("IPSec shared secret not specified\n"));
1177 return -1;
1178 }
1179
1180 encryptionType = CFDictionaryGetValue(newConfiguration, kSCPropNetIPSecSharedSecretEncryption);
1181 if (strlen(argv[0]) > 0) {
1182 if (encryptionType == NULL) {
1183 CFIndex n;
1184 CFMutableDataRef pw;
1185 CFStringRef str;
1186
1187 str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
1188 n = CFStringGetLength(str);
1189 pw = CFDataCreateMutable(NULL, n * sizeof(UniChar));
1190 CFDataSetLength(pw, n * sizeof(UniChar));
1191 CFStringGetCharacters(str,
1192 CFRangeMake(0, n),
1193 (UniChar *)CFDataGetMutableBytePtr(pw));
1194 CFRelease(str);
1195
1196 CFDictionarySetValue(newConfiguration, key, pw);
1197 CFRelease(pw);
1198 } else if (CFEqual(encryptionType, kSCValNetIPSecSharedSecretEncryptionKeychain)) {
1199 Boolean ok;
1200 CFDataRef pw;
1201 CFStringRef str;
1202
1203 str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
1204 pw = CFStringCreateExternalRepresentation(NULL, str, kCFStringEncodingUTF8, 0);
1205 ok = SCNetworkInterfaceSetPassword(net_interface,
1206 kSCNetworkInterfacePasswordTypeIPSecSharedSecret,
1207 pw,
1208 NULL);
1209 CFRelease(pw);
1210 CFRelease(str);
1211 if (ok) {
1212 updateInterfaceConfiguration(newConfiguration);
1213 } else {
1214 return -1;
1215 }
1216 } else {
1217 SCPrint(TRUE, stdout, CFSTR("IPSec shared secret type \"%@\" not supported\n"), encryptionType);
1218 return -1;
1219 }
1220 } else {
1221 if (encryptionType == NULL) {
1222 CFDictionaryRemoveValue(newConfiguration, key);
1223 } else if (CFEqual(encryptionType, kSCValNetIPSecSharedSecretEncryptionKeychain)) {
1224 Boolean ok;
1225 ok = SCNetworkInterfaceRemovePassword(net_interface, kSCNetworkInterfacePasswordTypeIPSecSharedSecret);
1226 if (ok) {
1227 updateInterfaceConfiguration(newConfiguration);
1228 } else {
1229 return -1;
1230 }
1231 } else {
1232 SCPrint(TRUE, stdout, CFSTR("IPSec shared secret type \"%@\" not supported\n"), encryptionType);
1233 return -1;
1234 }
1235 }
1236
1237 return 1;
1238 }
1239
1240
1241 static int
1242 __doIPSecSharedSecretType(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1243 {
1244 if (argc < 1) {
1245 SCPrint(TRUE, stdout, CFSTR("IPSec shared secret type mode not specified\n"));
1246 return -1;
1247 }
1248
1249 if (strlen(argv[0]) > 0) {
1250 if (strcasecmp(argv[0], "keychain") == 0) {
1251 CFDictionarySetValue(newConfiguration, key, kSCValNetIPSecSharedSecretEncryptionKeychain);
1252 } else {
1253 SCPrint(TRUE, stdout, CFSTR("invalid shared secret type\n"));
1254 return -1;
1255 }
1256 } else {
1257 CFDictionaryRemoveValue(newConfiguration, key);
1258 }
1259
1260 // encryption type changed, reset shared secret
1261 CFDictionaryRemoveValue(newConfiguration, kSCPropNetIPSecSharedSecret);
1262
1263 return 1;
1264 }
1265
1266
1267 static int
1268 __doIPSecXAuthPassword(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1269 {
1270 CFStringRef encryptionType;
1271
1272 if (argc < 1) {
1273 SCPrint(TRUE, stdout, CFSTR("IPSec XAuth password not specified\n"));
1274 return -1;
1275 }
1276
1277 encryptionType = CFDictionaryGetValue(newConfiguration, kSCPropNetIPSecXAuthPasswordEncryption);
1278 if (strlen(argv[0]) > 0) {
1279 if (encryptionType == NULL) {
1280 CFIndex n;
1281 CFMutableDataRef pw;
1282 CFStringRef str;
1283
1284 str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
1285 n = CFStringGetLength(str);
1286 pw = CFDataCreateMutable(NULL, n * sizeof(UniChar));
1287 CFDataSetLength(pw, n * sizeof(UniChar));
1288 CFStringGetCharacters(str,
1289 CFRangeMake(0, n),
1290 (UniChar *)CFDataGetMutableBytePtr(pw));
1291 CFRelease(str);
1292
1293 CFDictionarySetValue(newConfiguration, key, pw);
1294 CFRelease(pw);
1295 } else if (CFEqual(encryptionType, kSCValNetIPSecXAuthPasswordEncryptionKeychain)) {
1296 Boolean ok;
1297 CFDataRef pw;
1298 CFStringRef str;
1299
1300 str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
1301 pw = CFStringCreateExternalRepresentation(NULL, str, kCFStringEncodingUTF8, 0);
1302 ok = SCNetworkInterfaceSetPassword(net_interface,
1303 kSCNetworkInterfacePasswordTypeIPSecXAuth,
1304 pw,
1305 NULL);
1306 CFRelease(pw);
1307 CFRelease(str);
1308 if (ok) {
1309 updateInterfaceConfiguration(newConfiguration);
1310 } else {
1311 return -1;
1312 }
1313 } else {
1314 SCPrint(TRUE, stdout, CFSTR("IPSec XAuthPassword type \"%@\" not supported\n"), encryptionType);
1315 return -1;
1316 }
1317 } else {
1318 if (encryptionType == NULL) {
1319 CFDictionaryRemoveValue(newConfiguration, key);
1320 } else if (CFEqual(encryptionType, kSCValNetIPSecXAuthPasswordEncryptionKeychain)) {
1321 Boolean ok;
1322
1323 ok = SCNetworkInterfaceRemovePassword(net_interface, kSCNetworkInterfacePasswordTypeIPSecXAuth);
1324 if (ok) {
1325 updateInterfaceConfiguration(newConfiguration);
1326 } else {
1327 return -1;
1328 }
1329 } else {
1330 SCPrint(TRUE, stdout, CFSTR("IPSec XAuthPassword type \"%@\" not supported\n"), encryptionType);
1331 return -1;
1332 }
1333 }
1334
1335 return 1;
1336 }
1337
1338
1339 static int
1340 __doIPSecXAuthPasswordType(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1341 {
1342 if (argc < 1) {
1343 SCPrint(TRUE, stdout, CFSTR("IPSec XAuth password type mode not specified\n"));
1344 return -1;
1345 }
1346
1347 if (strlen(argv[0]) > 0) {
1348 if (strcasecmp(argv[0], "keychain") == 0) {
1349 CFDictionarySetValue(newConfiguration, key, kSCValNetIPSecXAuthPasswordEncryptionKeychain);
1350 } else {
1351 SCPrint(TRUE, stdout, CFSTR("invalid XAuth password type\n"));
1352 return -1;
1353 }
1354 } else {
1355 CFDictionaryRemoveValue(newConfiguration, key);
1356 }
1357
1358 // encryption type changed, reset XAuthPassword
1359 CFDictionaryRemoveValue(newConfiguration, kSCPropNetIPSecXAuthPassword);
1360
1361 return 1;
1362 }
1363
1364
1365 static CFStringRef
1366 __cleanupDomainName(CFStringRef domain)
1367 {
1368 CFMutableStringRef newDomain;
1369
1370 newDomain = CFStringCreateMutableCopy(NULL, 0, domain);
1371 CFStringTrimWhitespace(newDomain);
1372 CFStringTrim(newDomain, CFSTR("."));
1373 if (CFStringGetLength(newDomain) == 0) {
1374 CFRelease(newDomain);
1375 newDomain = NULL;
1376 }
1377
1378 return newDomain;
1379 }
1380
1381
1382 static int
1383 __doOnDemandDomains(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1384 {
1385 CFMutableArrayRef domains;
1386
1387 if (argc < 1) {
1388 SCPrint(TRUE, stdout, CFSTR("OnDemand domain name(s) not specified\n"));
1389 return -1;
1390 }
1391
1392 domains = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1393
1394 if (strlen(argv[0]) > 0) {
1395 CFArrayRef array;
1396 CFStringRef str;
1397
1398 str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
1399 array = CFStringCreateArrayBySeparatingStrings(NULL, str, CFSTR(","));
1400 CFRelease(str);
1401
1402 if (array != NULL) {
1403 CFIndex i;
1404 CFIndex n = CFArrayGetCount(array);
1405
1406 for (i = 0; i < n; i++) {
1407 CFStringRef domain;
1408
1409 domain = __cleanupDomainName(CFArrayGetValueAtIndex(array, i));
1410 if (domain != NULL) {
1411 CFArrayAppendValue(domains, domain);
1412 CFRelease(domain);
1413 } else {
1414 CFRelease(array);
1415 CFRelease(domains);
1416 SCPrint(TRUE, stdout, CFSTR("invalid OnDemand domain name\n"));
1417 return -1;
1418 }
1419 }
1420 CFRelease(array);
1421 }
1422 }
1423
1424 if (CFArrayGetCount(domains) > 0) {
1425 CFDictionarySetValue(newConfiguration, key, domains);
1426 } else {
1427 CFDictionaryRemoveValue(newConfiguration, key);
1428 }
1429
1430 CFRelease(domains);
1431 return 1;
1432 }
1433
1434
1435 static options ipsecOnDemandOptions[] = {
1436 { "OnDemandMatchDomainsAlways" , "domain", isOther , &kSCPropNetIPSecOnDemandMatchDomainsAlways , __doOnDemandDomains, NULL },
1437 { "always" , "domain", isOther , &kSCPropNetIPSecOnDemandMatchDomainsAlways , __doOnDemandDomains, NULL },
1438 { "OnDemandMatchDomainsOnRetry", "domain", isOther , &kSCPropNetIPSecOnDemandMatchDomainsOnRetry, __doOnDemandDomains, NULL },
1439 { "retry" , "domain", isOther , &kSCPropNetIPSecOnDemandMatchDomainsOnRetry, __doOnDemandDomains, NULL },
1440 { "OnDemandMatchDomainsNever" , "domain", isOther , &kSCPropNetIPSecOnDemandMatchDomainsNever , __doOnDemandDomains, NULL },
1441 { "never" , "domain", isOther , &kSCPropNetIPSecOnDemandMatchDomainsNever , __doOnDemandDomains, NULL },
1442
1443 { "?" , NULL , isHelp , NULL , NULL ,
1444 "\nOnDemandMatch configuration commands\n\n"
1445 " set interface OnDemandMatch always domain-name[,domain-name]\n"
1446 " set interface OnDemandMatch retry domain-name[,domain-name]\n"
1447 " set interface OnDemandMatch never domain-name[,domain-name]\n"
1448 }
1449 };
1450 #define N_IPSEC_ONDEMAND_OPTIONS (sizeof(ipsecOnDemandOptions) / sizeof(ipsecOnDemandOptions[0]))
1451
1452
1453 static int
1454 __doIPSecOnDemandMatch(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1455 {
1456 Boolean ok;
1457
1458 if (argc < 1) {
1459 SCPrint(TRUE, stdout, CFSTR("set what?\n"));
1460 return -1;
1461 }
1462
1463 ok = _process_options(ipsecOnDemandOptions, N_IPSEC_ONDEMAND_OPTIONS, argc, argv, newConfiguration);
1464 if (!ok) {
1465 goto done;
1466 }
1467
1468 done :
1469
1470 return argc;
1471 }
1472
1473
1474 static selections ipsecAuthenticationMethodSelections[] = {
1475 { CFSTR("SharedSecret"), &kSCValNetIPSecAuthenticationMethodSharedSecret, 0 },
1476 { CFSTR("Certificate") , &kSCValNetIPSecAuthenticationMethodCertificate , 0 },
1477 { CFSTR("Hybrid") , &kSCValNetIPSecAuthenticationMethodHybrid , 0 },
1478 { NULL , NULL , 0 }
1479 };
1480
1481
1482 static selections ipsecLocalIdentifierTypeSelections[] = {
1483 { CFSTR("KeyID") , &kSCValNetIPSecLocalIdentifierTypeKeyID , 0 },
1484 { NULL , NULL , 0 }
1485 };
1486
1487
1488 static options ipsecOptions[] = {
1489 { "AuthenticationMethod" , NULL, isChooseOne , &kSCPropNetIPSecAuthenticationMethod , NULL , (void *)ipsecAuthenticationMethodSelections },
1490 { "LocalIdentifier" , NULL, isString , &kSCPropNetIPSecLocalIdentifier , NULL , NULL },
1491 { "group" , NULL, isString , &kSCPropNetIPSecLocalIdentifier , NULL , NULL },
1492 { "LocalIdentifierType" , NULL, isChooseOne , &kSCPropNetIPSecLocalIdentifierType , NULL , (void *)ipsecLocalIdentifierTypeSelections },
1493 { "RemoteAddress" , NULL, isString , &kSCPropNetIPSecRemoteAddress , NULL , NULL },
1494 { "SharedSecret" , NULL, isOther , &kSCPropNetIPSecSharedSecret , __doIPSecSharedSecret , NULL },
1495 { "SharedSecretEncryption" , NULL, isOther , &kSCPropNetIPSecSharedSecretEncryption , __doIPSecSharedSecretType , NULL },
1496
1497 // --- XAuth: ---
1498 { "XAuthEnabled" , NULL, isBoolean , &kSCPropNetIPSecXAuthEnabled , NULL , NULL },
1499 { "XAuthName" , NULL, isString , &kSCPropNetIPSecXAuthName , NULL , NULL },
1500 { "XAuthPassword" , NULL, isOther , &kSCPropNetIPSecXAuthPassword , __doIPSecXAuthPassword , NULL },
1501 { "XAuthPasswordEncryption", NULL, isOther , &kSCPropNetIPSecXAuthPasswordEncryption, __doIPSecXAuthPasswordType, NULL },
1502
1503 // --- OnDemand: ---
1504 { "OnDemandEnabled" , NULL, isBoolean , &kSCPropNetIPSecOnDemandEnabled , NULL , NULL },
1505 { "OnDemandMatch" , NULL, isOther , NULL , __doIPSecOnDemandMatch , NULL },
1506
1507 { "?" , NULL , isHelp , NULL , NULL,
1508 "\nIPSec configuration commands\n\n"
1509 " set interface [AuthenticationMethod {SharedSecret|Certificate|Hybrid}]\n"
1510 " set interface [LocalIdentifier group]\n"
1511 " set interface [LocalIdentifierType {KeyID}]\n"
1512 " set interface [RemoteAddress name-or-address]\n"
1513 " set interface [SharedSecret secret]\n"
1514 " set interface [SharedSecretEncryption {Keychain}]\n"
1515 " set interface [XAuthEnabled {enable|disable}]\n"
1516 " set interface [XAuthPassword password]\n"
1517 " set interface [XAuthPasswordEncryption {Keychain}]\n"
1518 " set interface [OnDemandEnabled {enable|disable}]\n"
1519 " set interface [OnDemandMatch <match-options>]\n"
1520 }
1521 };
1522 #define N_IPSEC_OPTIONS (sizeof(ipsecOptions) / sizeof(ipsecOptions[0]))
1523
1524
1525 static Boolean
1526 set_interface_ipsec(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1527 {
1528 Boolean ok;
1529
1530 ok = _process_options(ipsecOptions, N_IPSEC_OPTIONS, argc, argv, newConfiguration);
1531 return ok;
1532 }
1533
1534
1535 #pragma mark -
1536 #pragma mark FireWire options
1537
1538
1539 static options firewireOptions[] = {
1540 { "mtu" , NULL, isNumber , &kSCPropNetEthernetMTU , NULL, NULL },
1541 { "media" , NULL, isString , &kSCPropNetEthernetMediaSubType, NULL, NULL },
1542 { "mediaopt" , NULL, isStringArray, &kSCPropNetEthernetMediaOptions, NULL, NULL },
1543
1544 { "?" , NULL , isHelp , NULL , NULL,
1545 "\nFireWire configuration commands\n\n"
1546 " set interface [mtu n] [media type] [mediaopts opts]\n"
1547 }
1548 };
1549 #define N_FIREWIRE_OPTIONS (sizeof(firewireOptions) / sizeof(firewireOptions[0]))
1550
1551
1552 static Boolean
1553 set_interface_firewire(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1554 {
1555 CFStringRef interfaceName;
1556 Boolean ok;
1557
1558 interfaceName = SCNetworkInterfaceGetBSDName(net_interface);
1559 if (interfaceName == NULL) {
1560 SCPrint(TRUE, stdout, CFSTR("no BSD interface\n"));
1561 return FALSE;
1562 }
1563
1564 ok = _process_options(firewireOptions, N_FIREWIRE_OPTIONS, argc, argv, newConfiguration);
1565 if (ok) {
1566 // validate configuration
1567 if (!validateMediaOptions(net_interface, newConfiguration)) {
1568 return FALSE;
1569 }
1570 }
1571
1572 return ok;
1573 }
1574
1575
1576 #pragma mark -
1577 #pragma mark Modem options
1578
1579
1580 static selections modemDialSelections[] = {
1581 { CFSTR("ignore"), &kSCValNetModemDialModeIgnoreDialTone , 0 },
1582 { CFSTR("manual"), &kSCValNetModemDialModeManual , 0 },
1583 { CFSTR("wait") , &kSCValNetModemDialModeWaitForDialTone, 0 },
1584 { NULL , NULL , 0 }
1585 };
1586
1587 static options modemOptions[] = {
1588 { "ConnectionScript" , "script", isString , &kSCPropNetModemConnectionScript , NULL, NULL },
1589 { "DialMode" , "mode" , isChooseOne, &kSCPropNetModemDialMode , NULL, (void *)modemDialSelections },
1590 { "CallWaiting" , NULL , isBoolean , &kSCPropNetModemHoldEnabled , NULL, NULL },
1591 { "CallWaitingAlert" , NULL , isBoolean , &kSCPropNetModemHoldCallWaitingAudibleAlert, NULL, NULL },
1592 { "CallWaitingDisconnectOnAnswer", NULL , isBoolean , &kSCPropNetModemHoldDisconnectOnAnswer , NULL, NULL },
1593 { "DataCompression" , NULL , isBoolean , &kSCPropNetModemDataCompression , NULL, NULL },
1594 { "ErrorCorrection" , NULL , isBoolean , &kSCPropNetModemErrorCorrection , NULL, NULL },
1595 { "HoldReminder" , NULL , isBoolean , &kSCPropNetModemHoldReminder , NULL, NULL },
1596 { "HoldReminderTime" , "time" , isNumber , &kSCPropNetModemHoldReminderTime , NULL, NULL },
1597 { "PulseDial" , NULL , isBoolean , &kSCPropNetModemPulseDial , NULL, NULL },
1598 { "Speaker" , NULL , isBoolean , &kSCPropNetModemSpeaker , NULL, NULL },
1599
1600 { "?" , NULL , isHelp , NULL , NULL,
1601 "\nModem configuration commands\n\n"
1602 " set interface [ConnectionScript connection-script]\n"
1603 " set interface [CallWaiting {enable|disable}]\n"
1604 " set interface [CallWaitingAlert {enable|disable}]\n"
1605 " set interface [CallWaitingDisconnectOnAnswer {enable|disable}]\n"
1606 " set interface [DialMode {ignore|wait}]\n"
1607 " set interface [DataCompression {enable|disable}]\n"
1608 " set interface [ErrorCorrection {enable|disable}]\n"
1609 " set interface [HoldReminder {enable|disable}]\n"
1610 " set interface [HoldReminderTime n]\n"
1611 " set interface [PulseDial {enable|disable}]\n"
1612 " set interface [Speaker {enable|disable}]\n"
1613 }
1614 };
1615 #define N_MODEM_OPTIONS (sizeof(modemOptions) / sizeof(modemOptions[0]))
1616
1617
1618 static Boolean
1619 set_interface_modem(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1620 {
1621 Boolean ok;
1622
1623 ok = _process_options(modemOptions, N_MODEM_OPTIONS, argc, argv, newConfiguration);
1624 return ok;
1625 }
1626
1627
1628 #pragma mark -
1629 #pragma mark PPP options
1630
1631
1632 static int
1633 __doPPPAuthPW(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1634 {
1635 CFStringRef encryptionType;
1636
1637 if (argc < 1) {
1638 SCPrint(TRUE, stdout, CFSTR("PPP password not specified\n"));
1639 return -1;
1640 }
1641
1642 encryptionType = CFDictionaryGetValue(newConfiguration, kSCPropNetPPPAuthPasswordEncryption);
1643 if (strlen(argv[0]) > 0) {
1644 if (encryptionType == NULL) {
1645 CFIndex n;
1646 CFMutableDataRef pw;
1647 CFStringRef str;
1648
1649 str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
1650 n = CFStringGetLength(str);
1651 pw = CFDataCreateMutable(NULL, n * sizeof(UniChar));
1652 CFDataSetLength(pw, n * sizeof(UniChar));
1653 CFStringGetCharacters(str,
1654 CFRangeMake(0, n),
1655 (UniChar *)CFDataGetMutableBytePtr(pw));
1656 CFRelease(str);
1657
1658 CFDictionarySetValue(newConfiguration, key, pw);
1659 CFRelease(pw);
1660 } else if (CFEqual(encryptionType, kSCValNetPPPAuthPasswordEncryptionKeychain)) {
1661 Boolean ok;
1662 CFDataRef pw;
1663 CFStringRef str;
1664
1665 str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
1666 pw = CFStringCreateExternalRepresentation(NULL, str, kCFStringEncodingUTF8, 0);
1667 ok = SCNetworkInterfaceSetPassword(net_interface,
1668 kSCNetworkInterfacePasswordTypePPP,
1669 pw,
1670 NULL);
1671 CFRelease(pw);
1672 CFRelease(str);
1673 if (ok) {
1674 updateInterfaceConfiguration(newConfiguration);
1675 } else {
1676 return -1;
1677 }
1678 } else {
1679 SCPrint(TRUE, stdout, CFSTR("PPP password type \"%@\" not supported\n"), encryptionType);
1680 return -1;
1681 }
1682 } else {
1683 if (encryptionType == NULL) {
1684 CFDictionaryRemoveValue(newConfiguration, key);
1685 } else if (CFEqual(encryptionType, kSCValNetPPPAuthPasswordEncryptionKeychain)) {
1686 Boolean ok;
1687
1688 ok = SCNetworkInterfaceRemovePassword(net_interface, kSCNetworkInterfacePasswordTypePPP);
1689 if (ok) {
1690 updateInterfaceConfiguration(newConfiguration);
1691 } else {
1692 return -1;
1693 }
1694 } else {
1695 SCPrint(TRUE, stdout, CFSTR("PPP password type \"%@\" not supported\n"), encryptionType);
1696 return -1;
1697 }
1698 }
1699
1700 return 1;
1701 }
1702
1703
1704 static int
1705 __doPPPAuthPWType(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1706 {
1707 if (argc < 1) {
1708 SCPrint(TRUE, stdout, CFSTR("PPP password type mode not specified\n"));
1709 return -1;
1710 }
1711
1712 if (strlen(argv[0]) > 0) {
1713 if (strcasecmp(argv[0], "keychain") == 0) {
1714 CFDictionarySetValue(newConfiguration, key, kSCValNetPPPAuthPasswordEncryptionKeychain);
1715 } else {
1716 SCPrint(TRUE, stdout, CFSTR("invalid password type\n"));
1717 return -1;
1718 }
1719 } else {
1720 CFDictionaryRemoveValue(newConfiguration, key);
1721 }
1722
1723 // encryption type changed, reset password
1724 CFDictionaryRemoveValue(newConfiguration, kSCPropNetPPPAuthPassword);
1725
1726 return 1;
1727 }
1728
1729
1730 static options l2tp_ipsecOptions[] = {
1731 { "SharedSecret" , NULL, isOther , &kSCPropNetIPSecSharedSecret , __doIPSecSharedSecret , NULL },
1732 { "SharedSecretEncryption", NULL, isOther , &kSCPropNetIPSecSharedSecretEncryption, __doIPSecSharedSecretType, NULL },
1733
1734 { "?" , NULL , isHelp , NULL , NULL,
1735 "\nIPSec configuration commands\n\n"
1736 " set interface ipsec [SharedSecret secret]\n"
1737 " set interface ipsec [SharedSecretEncryption {Keychain}]\n"
1738 }
1739 };
1740 #define N_L2TP_IPSEC_OPTIONS (sizeof(l2tp_ipsecOptions) / sizeof(l2tp_ipsecOptions[0]))
1741
1742
1743 static int
1744 __doPPPIPSec(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newPPPConfiguration)
1745 {
1746 SCNetworkInterfaceRef childInterface;
1747 CFStringRef childInterfaceType;
1748 CFDictionaryRef configuration;
1749 CFMutableDictionaryRef newConfiguration;
1750 Boolean ok;
1751
1752 if (argc < 1) {
1753 SCPrint(TRUE, stdout, CFSTR("set what?\n"));
1754 return -1;
1755 }
1756
1757 childInterface = SCNetworkInterfaceGetInterface(net_interface);
1758 if (childInterface == NULL) {
1759 SCPrint(TRUE, stdout, CFSTR("this interfaces configuration cannot be changed\n"));
1760 return -1;
1761 }
1762
1763 childInterfaceType = SCNetworkInterfaceGetInterfaceType(childInterface);
1764 if (!CFEqual(childInterfaceType, kSCNetworkInterfaceTypeL2TP)) {
1765 SCPrint(TRUE, stdout, CFSTR("this interfaces configuration cannot be changed\n"));
1766 return -1;
1767 }
1768
1769 configuration = SCNetworkInterfaceGetExtendedConfiguration(net_interface, kSCEntNetIPSec);
1770 if (configuration == NULL) {
1771 newConfiguration = CFDictionaryCreateMutable(NULL,
1772 0,
1773 &kCFTypeDictionaryKeyCallBacks,
1774 &kCFTypeDictionaryValueCallBacks);
1775 } else {
1776 newConfiguration = CFDictionaryCreateMutableCopy(NULL, 0, configuration);
1777 CFDictionaryRemoveValue(newConfiguration, kSCResvInactive);
1778 }
1779
1780 ok = _process_options(l2tp_ipsecOptions, N_L2TP_IPSEC_OPTIONS, argc, argv, newConfiguration);
1781 if (!ok) {
1782 goto done;
1783 }
1784
1785 if (((configuration == NULL) && (CFDictionaryGetCount(newConfiguration) > 0)) ||
1786 ((configuration != NULL) && !CFEqual(configuration, newConfiguration))) {
1787 if (!SCNetworkInterfaceSetExtendedConfiguration(net_interface, kSCEntNetIPSec, newConfiguration)) {
1788 if (SCError() == kSCStatusNoKey) {
1789 SCPrint(TRUE, stdout, CFSTR("could not update per-service interface configuration\n"));
1790 } else {
1791 SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
1792 }
1793 goto done;
1794 }
1795
1796 _prefs_changed = TRUE;
1797 }
1798
1799 done :
1800
1801 if (newConfiguration != NULL) CFRelease(newConfiguration);
1802 return argc;
1803 }
1804
1805
1806 #ifdef NOTYET
1807 static options pppOnDemandOptions[] = {
1808 { "OnDemandMatchDomainsAlways" , "domain", isOther , &kSCPropNetPPPOnDemandMatchDomainsAlways , __doOnDemandDomains, NULL },
1809 { "always" , "domain", isOther , &kSCPropNetPPPOnDemandMatchDomainsAlways , __doOnDemandDomains, NULL },
1810 { "OnDemandMatchDomainsOnRetry", "domain", isOther , &kSCPropNetPPPOnDemandMatchDomainsOnRetry, __doOnDemandDomains, NULL },
1811 { "retry" , "domain", isOther , &kSCPropNetPPPOnDemandMatchDomainsOnRetry, __doOnDemandDomains, NULL },
1812 { "OnDemandMatchDomainsNever" , "domain", isOther , &kSCPropNetPPPOnDemandMatchDomainsNever , __doOnDemandDomains, NULL },
1813 { "never" , "domain", isOther , &kSCPropNetPPPOnDemandMatchDomainsNever , __doOnDemandDomains, NULL },
1814
1815 { "?" , NULL , isHelp , NULL , NULL ,
1816 "\nOnDemandMatch configuration commands\n\n"
1817 " set interface OnDemand always domain-name[,domain-name]\n"
1818 " set interface OnDemand retry domain-name[,domain-name]\n"
1819 " set interface OnDemand never domain-name[,domain-name]\n"
1820 }
1821 };
1822 #define N_PPP_ONDEMAND_OPTIONS (sizeof(pppOnDemandOptions) / sizeof(pppOnDemandOptions[0]))
1823
1824
1825 static int
1826 __doPPPOnDemandMatch(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1827 {
1828 Boolean ok;
1829
1830 if (argc < 1) {
1831 SCPrint(TRUE, stdout, CFSTR("set what?\n"));
1832 return -1;
1833 }
1834
1835 ok = _process_options(pppOnDemandOptions, N_PPP_ONDEMAND_OPTIONS, argc, argv, newConfiguration);
1836 if (!ok) {
1837 goto done;
1838 }
1839
1840 done :
1841
1842 return argc;
1843 }
1844 #endif // NOTYET
1845
1846
1847 static selections authPromptSelections[] = {
1848 { CFSTR("before"), &kSCValNetPPPAuthPromptBefore, 0 },
1849 { CFSTR("after") , &kSCValNetPPPAuthPromptAfter , 0 },
1850 { NULL , NULL , 0 }
1851 };
1852
1853
1854 static selections authProtocolSelections[] = {
1855 { CFSTR("CHAP") , &kSCValNetPPPAuthProtocolCHAP , 0 },
1856 { CFSTR("EAP") , &kSCValNetPPPAuthProtocolEAP , 0 },
1857 { CFSTR("MSCHAP1"), &kSCValNetPPPAuthProtocolMSCHAP1, 0 },
1858 { CFSTR("MSCHAP2"), &kSCValNetPPPAuthProtocolMSCHAP2, 0 },
1859 { CFSTR("PAP") , &kSCValNetPPPAuthProtocolPAP , 0 },
1860 { NULL , NULL , 0 }
1861 };
1862
1863
1864 static options pppOptions[] = {
1865 { "ACSP" , NULL , isBoolean , &kSCPropNetPPPACSPEnabled , NULL , NULL },
1866 { "ConnectTime" , "?time" , isNumber , &kSCPropNetPPPConnectTime , NULL , NULL },
1867 { "DialOnDemand" , NULL , isBoolean , &kSCPropNetPPPDialOnDemand , NULL , NULL },
1868 { "DisconnectOnFastUserSwitch", NULL , isBoolean , &kSCPropNetPPPDisconnectOnFastUserSwitch, NULL , NULL },
1869 { "DisconnectOnIdle" , NULL , isBoolean , &kSCPropNetPPPDisconnectOnIdle , NULL , NULL },
1870 { "DisconnectOnIdleTimer" , "timeout" , isNumber , &kSCPropNetPPPDisconnectOnIdleTimer , NULL , NULL },
1871 { "DisconnectOnLogout" , NULL , isBoolean , &kSCPropNetPPPDisconnectOnLogout , NULL , NULL },
1872 { "DisconnectOnSleep" , NULL , isBoolean , &kSCPropNetPPPDisconnectOnSleep , NULL , NULL },
1873 { "DisconnectTime" , "?time" , isNumber , &kSCPropNetPPPDisconnectTime , NULL , NULL },
1874 { "IdleReminder" , NULL , isBoolean , &kSCPropNetPPPIdleReminder , NULL , NULL },
1875 { "IdleReminderTimer" , "time" , isNumber , &kSCPropNetPPPIdleReminderTimer , NULL , NULL },
1876 { "Logfile" , "path" , isString , &kSCPropNetPPPLogfile , NULL , NULL },
1877 { "Plugins" , "plugin" , isStringArray , &kSCPropNetPPPPlugins , NULL , NULL },
1878 { "RetryConnectTime" , "time" , isNumber , &kSCPropNetPPPRetryConnectTime , NULL , NULL },
1879 { "SessionTimer" , "time" , isNumber , &kSCPropNetPPPSessionTimer , NULL , NULL },
1880 { "UseSessionTimer" , NULL , isBoolean , &kSCPropNetPPPUseSessionTimer , NULL , NULL },
1881 { "VerboseLogging" , NULL , isBoolean , &kSCPropNetPPPVerboseLogging , NULL , NULL },
1882
1883 // --- Auth: ---
1884 { "AuthEAPPlugins" , "plugin" , isStringArray , &kSCPropNetPPPAuthEAPPlugins , NULL , NULL },
1885 { "AuthName" , "account" , isString , &kSCPropNetPPPAuthName , NULL , NULL },
1886 { "Account" , "account" , isString , &kSCPropNetPPPAuthName , NULL , NULL },
1887 { "AuthPassword" , "password" , isOther , &kSCPropNetPPPAuthPassword , __doPPPAuthPW , NULL },
1888 { "Password" , "password" , isOther , &kSCPropNetPPPAuthPassword , __doPPPAuthPW , NULL },
1889 { "AuthPasswordEncryption" , "type" , isOther , &kSCPropNetPPPAuthPasswordEncryption , __doPPPAuthPWType , NULL },
1890 { "AuthPrompt" , "before/after", isChooseOne , &kSCPropNetPPPAuthPrompt , NULL , (void *)authPromptSelections },
1891 { "AuthProtocol" , "protocol" , isChooseMultiple , &kSCPropNetPPPAuthProtocol , NULL , (void *)authProtocolSelections },
1892
1893 // --- Comm: ---
1894 { "CommRemoteAddress" , "phone#" , isString , &kSCPropNetPPPCommRemoteAddress , NULL , NULL },
1895 { "CommAlternateRemoteAddress", "phone#" , isString , &kSCPropNetPPPCommAlternateRemoteAddress, NULL , NULL },
1896 { "CommConnectDelay" , "time" , isNumber , &kSCPropNetPPPCommConnectDelay , NULL , NULL },
1897 { "CommDisplayTerminalWindow" , NULL , isBoolean , &kSCPropNetPPPCommDisplayTerminalWindow , NULL , NULL },
1898 { "CommRedialCount" , "retry count" , isNumber , &kSCPropNetPPPCommRedialCount , NULL , NULL },
1899 { "CommRedialEnabled" , NULL , isBoolean , &kSCPropNetPPPCommRedialEnabled , NULL , NULL },
1900 { "CommRedialInterval" , "retry delay" , isNumber , &kSCPropNetPPPCommRedialInterval , NULL , NULL },
1901 { "CommTerminalScript" , "script" , isString , &kSCPropNetPPPCommTerminalScript , NULL , NULL },
1902 { "CommUseTerminalScript" , NULL , isBoolean , &kSCPropNetPPPCommUseTerminalScript , NULL , NULL },
1903
1904 // --- CCP: ---
1905 { "CCPEnabled" , NULL , isBoolean , &kSCPropNetPPPCCPEnabled , NULL , NULL },
1906 { "CCPMPPE40Enabled" , NULL , isBoolean , &kSCPropNetPPPCCPMPPE40Enabled , NULL , NULL },
1907 { "CCPMPPE128Enabled" , NULL , isBoolean , &kSCPropNetPPPCCPMPPE128Enabled , NULL , NULL },
1908
1909 // --- IPCP: ---
1910 { "IPCPCompressionVJ" , NULL , isBoolean , &kSCPropNetPPPIPCPCompressionVJ , NULL , NULL },
1911 { "IPCPUsePeerDNS" , NULL , isBoolean , &kSCPropNetPPPIPCPUsePeerDNS , NULL , NULL },
1912
1913 // --- LCP: ---
1914 { "LCPEchoEnabled" , NULL , isBoolean , &kSCPropNetPPPLCPEchoEnabled , NULL , NULL },
1915 { "LCPEchoFailure" , NULL , isNumber , &kSCPropNetPPPLCPEchoFailure , NULL , NULL },
1916 { "LCPEchoInterval" , NULL , isNumber , &kSCPropNetPPPLCPEchoInterval , NULL , NULL },
1917 { "LCPCompressionACField" , NULL , isBoolean , &kSCPropNetPPPLCPCompressionACField , NULL , NULL },
1918 { "LCPCompressionPField" , NULL , isBoolean , &kSCPropNetPPPLCPCompressionPField , NULL , NULL },
1919 { "LCPMRU" , NULL , isNumber , &kSCPropNetPPPLCPMRU , NULL , NULL },
1920 { "LCPMTU" , NULL , isNumber , &kSCPropNetPPPLCPMTU , NULL , NULL },
1921 { "LCPReceiveACCM" , NULL , isNumber , &kSCPropNetPPPLCPReceiveACCM , NULL , NULL },
1922 { "LCPTransmitACCM" , NULL , isNumber , &kSCPropNetPPPLCPTransmitACCM , NULL , NULL },
1923
1924 // --- IPSec: ---
1925 { "IPSec" , NULL , isOther , NULL , __doPPPIPSec , NULL },
1926
1927 #ifdef NOTYET
1928 // --- OnDemand: ---
1929 { "OnDemandEnabled" , NULL , isBoolean , &kSCPropNetPPPOnDemandEnabled , NULL , NULL },
1930 { "OnDemandMatch" , NULL , isOther , NULL , __doPPPOnDemandMatch, NULL },
1931 #endif // NOTYET
1932
1933 // --- Help ---
1934 { "?" , NULL , isHelp , NULL , NULL ,
1935 "\nPPP configuration commands\n\n"
1936 " set interface [Account account]\n"
1937 " set interface [Password password]\n"
1938 " set interface [Number telephone-number]\n"
1939 " set interface [AlternateNumber telephone-number]\n"
1940 " set interface [IdleReminder {enable|disable}]\n"
1941 " set interface [IdleReminderTimer time-in-seconds]\n"
1942 " set interface [DisconnectOnIdle {enable|disable}]\n"
1943 " set interface [DisconnectOnIdleTimer time-in-seconds]\n"
1944 " set interface [DisconnectOnLogout {enable|disable}]\n"
1945 " set interface [IPSec <ipsec-options>]\n"
1946 #ifdef NOTYET
1947 " set interface [OnDemandEnabled {enable|disable}]\n"
1948 " set interface [OnDemandMatch <match-options>]\n"
1949 #endif // NOTYET
1950 }
1951 };
1952 #define N_PPP_OPTIONS (sizeof(pppOptions) / sizeof(pppOptions[0]))
1953
1954
1955 static Boolean
1956 set_interface_ppp(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1957 {
1958 Boolean ok;
1959
1960 ok = _process_options(pppOptions, N_PPP_OPTIONS, argc, argv, newConfiguration);
1961 return ok;
1962 }
1963
1964
1965 #pragma mark -
1966 #pragma mark VLAN options
1967
1968
1969 static Boolean
1970 set_interface_vlan(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1971 {
1972 // xxxxx ("device", "tag")
1973 SCPrint(TRUE, stdout, CFSTR("vlan interface management not yet supported\n"));
1974 return FALSE;
1975 }
1976
1977
1978 #pragma mark -
1979 #pragma mark VPN options
1980
1981
1982 static int
1983 __doVPNAuthPW(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1984 {
1985 CFStringRef encryptionType;
1986
1987 if (argc < 1) {
1988 SCPrint(TRUE, stdout, CFSTR("VPN password not specified\n"));
1989 return -1;
1990 }
1991
1992 encryptionType = CFDictionaryGetValue(newConfiguration, kSCPropNetVPNAuthPasswordEncryption);
1993 if (strlen(argv[0]) > 0) {
1994 if (encryptionType == NULL) {
1995 #ifdef USE_INLINE_CFDATA
1996 CFIndex n;
1997 CFMutableDataRef pw;
1998 CFStringRef str;
1999
2000 str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
2001 n = CFStringGetLength(str);
2002 pw = CFDataCreateMutable(NULL, n * sizeof(UniChar));
2003 CFDataSetLength(pw, n * sizeof(UniChar));
2004 CFStringGetCharacters(str,
2005 CFRangeMake(0, n),
2006 (UniChar *)CFDataGetMutableBytePtr(pw));
2007 CFRelease(str);
2008 #else // USE_INLINE_CFDATA
2009 CFStringRef pw;
2010
2011 pw = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
2012 #endif // USE_INLINE_CFDATA
2013
2014 CFDictionarySetValue(newConfiguration, key, pw);
2015 CFRelease(pw);
2016 } else if (CFEqual(encryptionType, kSCValNetVPNAuthPasswordEncryptionKeychain)) {
2017 Boolean ok;
2018 CFDataRef pw;
2019 CFStringRef str;
2020
2021 str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
2022 pw = CFStringCreateExternalRepresentation(NULL, str, kCFStringEncodingUTF8, 0);
2023 ok = SCNetworkInterfaceSetPassword(net_interface,
2024 kSCNetworkInterfacePasswordTypeVPN,
2025 pw,
2026 NULL);
2027 CFRelease(pw);
2028 CFRelease(str);
2029 if (ok) {
2030 updateInterfaceConfiguration(newConfiguration);
2031 } else {
2032 return -1;
2033 }
2034 } else {
2035 SCPrint(TRUE, stdout, CFSTR("VPN password type \"%@\" not supported\n"), encryptionType);
2036 return -1;
2037 }
2038 } else {
2039 if (encryptionType == NULL) {
2040 CFDictionaryRemoveValue(newConfiguration, key);
2041 } else if (CFEqual(encryptionType, kSCValNetVPNAuthPasswordEncryptionKeychain)) {
2042 Boolean ok;
2043
2044 ok = SCNetworkInterfaceRemovePassword(net_interface, kSCNetworkInterfacePasswordTypeVPN);
2045 if (ok) {
2046 updateInterfaceConfiguration(newConfiguration);
2047 } else {
2048 return -1;
2049 }
2050 } else {
2051 SCPrint(TRUE, stdout, CFSTR("PPP password type \"%@\" not supported\n"), encryptionType);
2052 return -1;
2053 }
2054 }
2055
2056 return 1;
2057 }
2058
2059
2060 static int
2061 __doVPNAuthPWType(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
2062 {
2063 if (argc < 1) {
2064 SCPrint(TRUE, stdout, CFSTR("VPN password type mode not specified\n"));
2065 return -1;
2066 }
2067
2068 if (strlen(argv[0]) > 0) {
2069 if (strcasecmp(argv[0], "keychain") == 0) {
2070 CFDictionarySetValue(newConfiguration, key, kSCValNetVPNAuthPasswordEncryptionKeychain);
2071 } else if (strcasecmp(argv[0], "prompt") == 0) {
2072 CFDictionarySetValue(newConfiguration, key, kSCValNetVPNAuthPasswordEncryptionPrompt);
2073 } else {
2074 SCPrint(TRUE, stdout, CFSTR("invalid password type\n"));
2075 return -1;
2076 }
2077 } else {
2078 CFDictionaryRemoveValue(newConfiguration, key);
2079 }
2080
2081 // encryption type changed, reset password
2082 CFDictionaryRemoveValue(newConfiguration, kSCPropNetVPNAuthPassword);
2083
2084 return 1;
2085 }
2086
2087
2088 static selections vpnAuthenticationMethodSelections[] = {
2089 { CFSTR("Password") , &kSCValNetVPNAuthenticationMethodPassword , 0 },
2090 { CFSTR("Certificate") , &kSCValNetVPNAuthenticationMethodCertificate , 0 },
2091 { NULL , NULL , 0 }
2092 };
2093
2094
2095 static options vpnOptions[] = {
2096 { "AuthName" , "account" , isString , &kSCPropNetVPNAuthName , NULL , NULL },
2097 { "Account" , "account" , isString , &kSCPropNetVPNAuthName , NULL , NULL },
2098 { "AuthPassword" , "password" , isOther , &kSCPropNetVPNAuthPassword , __doVPNAuthPW , NULL },
2099 { "Password" , "password" , isOther , &kSCPropNetVPNAuthPassword , __doVPNAuthPW , NULL },
2100 { "AuthPasswordEncryption" , "type" , isOther , &kSCPropNetVPNAuthPasswordEncryption , __doVPNAuthPWType , NULL },
2101 { "AuthenticationMethod" , NULL , isChooseOne , &kSCPropNetVPNAuthenticationMethod , NULL , (void *)vpnAuthenticationMethodSelections },
2102 { "ConnectTime" , "?time" , isNumber , &kSCPropNetVPNConnectTime , NULL , NULL },
2103 { "DisconnectOnFastUserSwitch", NULL , isBoolean , &kSCPropNetVPNDisconnectOnFastUserSwitch, NULL , NULL },
2104 { "DisconnectOnIdle" , NULL , isBoolean , &kSCPropNetVPNDisconnectOnIdle , NULL , NULL },
2105 { "DisconnectOnIdleTimer" , "timeout" , isNumber , &kSCPropNetVPNDisconnectOnIdleTimer , NULL , NULL },
2106 { "DisconnectOnLogout" , NULL , isBoolean , &kSCPropNetVPNDisconnectOnLogout , NULL , NULL },
2107 { "DisconnectOnSleep" , NULL , isBoolean , &kSCPropNetVPNDisconnectOnSleep , NULL , NULL },
2108 { "Logfile" , "path" , isString , &kSCPropNetVPNLogfile , NULL , NULL },
2109 { "MTU" , NULL , isNumber , &kSCPropNetVPNMTU , NULL , NULL },
2110 { "RemoteAddress" , "server" , isString , &kSCPropNetVPNRemoteAddress , NULL , NULL },
2111 { "Server" , "server" , isString , &kSCPropNetVPNRemoteAddress , NULL , NULL },
2112 { "VerboseLogging" , NULL , isBoolean , &kSCPropNetVPNVerboseLogging , NULL , NULL },
2113
2114 // --- Help ---
2115 { "?" , NULL , isHelp , NULL , NULL ,
2116 "\nVPN configuration commands\n\n"
2117 " set interface [Server server]\n"
2118 " set interface [Account account]\n"
2119 " set interface [Password password]\n"
2120 }
2121 };
2122 #define N_VPN_OPTIONS (sizeof(vpnOptions) / sizeof(vpnOptions[0]))
2123
2124
2125 static Boolean
2126 set_interface_vpn(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
2127 {
2128 Boolean ok;
2129
2130 ok = _process_options(vpnOptions, N_VPN_OPTIONS, argc, argv, newConfiguration);
2131 return ok;
2132 }
2133
2134
2135 #pragma mark -
2136 #pragma mark [more] Interface management
2137
2138
2139 __private_extern__
2140 void
2141 set_interface(int argc, char **argv)
2142 {
2143 CFDictionaryRef configuration;
2144 CFStringRef interfaceType;
2145 CFMutableDictionaryRef newConfiguration = NULL;
2146 Boolean ok = FALSE;
2147
2148 if (net_interface == NULL) {
2149 SCPrint(TRUE, stdout, CFSTR("interface not selected\n"));
2150 return;
2151 }
2152
2153 if (argc < 1) {
2154 SCPrint(TRUE, stdout, CFSTR("set what?\n"));
2155 return;
2156 }
2157
2158 configuration = SCNetworkInterfaceGetConfiguration(net_interface);
2159 if (configuration != NULL) {
2160 configuration = CFDictionaryCreateCopy(NULL, configuration);
2161 newConfiguration = CFDictionaryCreateMutableCopy(NULL, 0, configuration);
2162 CFDictionaryRemoveValue(newConfiguration, kSCResvInactive);
2163 } else {
2164 newConfiguration = CFDictionaryCreateMutable(NULL,
2165 0,
2166 &kCFTypeDictionaryKeyCallBacks,
2167 &kCFTypeDictionaryValueCallBacks);
2168 }
2169
2170 interfaceType = SCNetworkInterfaceGetInterfaceType(net_interface);
2171
2172 if (CFEqual(interfaceType, kSCNetworkInterfaceTypeEthernet)) {
2173 ok = set_interface_ethernet(argc, argv, newConfiguration);
2174 } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeFireWire)) {
2175 ok = set_interface_firewire(argc, argv, newConfiguration);
2176 } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeIPSec)) {
2177 ok = set_interface_ipsec(argc, argv, newConfiguration);
2178 } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeModem)) {
2179 ok = set_interface_modem(argc, argv, newConfiguration);
2180 } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeIEEE80211)) {
2181 ok = set_interface_airport(argc, argv, newConfiguration);
2182 } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
2183 ok = set_interface_ppp(argc, argv, newConfiguration);
2184 } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBond)) {
2185 ok = set_interface_bond(argc, argv, newConfiguration);
2186 } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBridge)) {
2187 ok = set_interface_bridge(argc, argv, newConfiguration);
2188 } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVLAN)) {
2189 ok = set_interface_vlan(argc, argv, newConfiguration);
2190 } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVPN)) {
2191 ok = set_interface_vpn(argc, argv, newConfiguration);
2192 } else {
2193 SCPrint(TRUE, stdout, CFSTR("this interfaces configuration cannot be changed\n"));
2194 }
2195
2196 if (!ok) {
2197 goto done;
2198 }
2199
2200 if (((configuration == NULL) && (CFDictionaryGetCount(newConfiguration) > 0)) ||
2201 ((configuration != NULL) && !CFEqual(configuration, newConfiguration))) {
2202 if (!SCNetworkInterfaceSetConfiguration(net_interface, newConfiguration)) {
2203 if (SCError() == kSCStatusNoKey) {
2204 SCPrint(TRUE, stdout, CFSTR("could not update per-service interface configuration\n"));
2205 } else {
2206 SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
2207 }
2208 goto done;
2209 }
2210
2211 _prefs_changed = TRUE;
2212 }
2213
2214 done :
2215
2216 if (configuration != NULL) CFRelease(configuration);
2217 if (newConfiguration != NULL) CFRelease(newConfiguration);
2218 return;
2219 }
2220
2221
2222 /* -------------------- */
2223
2224
2225 __private_extern__
2226 void
2227 show_interface(int argc, char **argv)
2228 {
2229 SCNetworkInterfaceRef interface;
2230
2231 if (argc >= 1) {
2232 interface = _find_interface(argc, argv, NULL);
2233 } else {
2234 if (net_interface != NULL) {
2235 interface = net_interface;
2236 } else {
2237 SCPrint(TRUE, stdout, CFSTR("interface not selected\n"));
2238 return;
2239 }
2240 }
2241
2242 if (interface != NULL) {
2243 _show_interface(interface, CFSTR(""), TRUE);
2244 }
2245
2246 return;
2247 }
2248
2249
2250 /* -------------------- */
2251
2252
2253 __private_extern__
2254 CFStringRef
2255 _interface_description(SCNetworkInterfaceRef interface)
2256 {
2257 CFMutableStringRef description;
2258 CFStringRef if_bsd_name;
2259 CFStringRef if_type;
2260
2261 description = CFStringCreateMutable(NULL, 0);
2262
2263 if_type = SCNetworkInterfaceGetInterfaceType(interface);
2264 CFStringAppend(description, if_type);
2265
2266 if_bsd_name = SCNetworkInterfaceGetBSDName(interface);
2267 if (if_bsd_name != NULL) {
2268 CFStringAppendFormat(description, NULL, CFSTR(" (%@)"), if_bsd_name);
2269 }
2270
2271 interface = SCNetworkInterfaceGetInterface(interface);
2272 while ((interface != NULL) &&
2273 !CFEqual(interface, kSCNetworkInterfaceIPv4)) {
2274 CFStringRef childDescription;
2275
2276 childDescription = _interface_description(interface);
2277 CFStringAppendFormat(description, NULL, CFSTR(" / %@"), childDescription);
2278 CFRelease(childDescription);
2279
2280 interface = SCNetworkInterfaceGetInterface(interface);
2281 }
2282
2283 return description;
2284 }