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