]> git.saurik.com Git - apple/configd.git/blob - scutil.tproj/net_protocol.c
b0392fa270feed84f03dfe0b79d31db93aea2a85
[apple/configd.git] / scutil.tproj / net_protocol.c
1 /*
2 * Copyright (c) 2004-2009, 2011, 2014, 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 "scutil.h"
33 #include "net.h"
34 #include "net_protocol.h"
35 #include "prefs.h"
36
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <net/if.h>
40 #include <netinet/in.h>
41 #include <arpa/inet.h>
42
43
44 /* -------------------- */
45
46
47 static CFStringRef
48 __copyIPv4Address(const char *arg)
49 {
50 char buf[128];
51 struct sockaddr_in sin;
52
53 if (_SC_string_to_sockaddr(arg, AF_INET, (void *)&sin, sizeof(sin)) == NULL) {
54 return NULL;
55 }
56
57 _SC_sockaddr_to_string((struct sockaddr *)&sin, buf, sizeof(buf));
58 return CFStringCreateWithCString(NULL, buf, kCFStringEncodingUTF8);
59 }
60
61
62 static CFStringRef
63 __copyIPv6Address(const char *arg)
64 {
65 char buf[128];
66 struct sockaddr_in6 sin6;
67
68 if (_SC_string_to_sockaddr(arg, AF_INET6, (void *)&sin6, sizeof(sin6)) == NULL) {
69 return NULL;
70 }
71
72 _SC_sockaddr_to_string((struct sockaddr *)&sin6, buf, sizeof(buf));
73 return CFStringCreateWithCString(NULL, buf, kCFStringEncodingUTF8);
74 }
75
76
77 /* -------------------- */
78
79
80 static SCNetworkProtocolRef
81 _find_protocol(char *match)
82 {
83 Boolean allowIndex = TRUE;
84 CFIndex i;
85 CFIndex n;
86 CFStringRef select_name = NULL;
87 SCNetworkProtocolRef selected = NULL;
88
89 if (protocols == NULL) {
90 if (net_service == NULL) {
91 SCPrint(TRUE, stdout, CFSTR("network service not selected\n"));
92 return NULL;
93 }
94
95 protocols = SCNetworkServiceCopyProtocols(net_service);
96 if (protocols == NULL) {
97 SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
98 return NULL;
99 }
100
101 n = CFArrayGetCount(protocols);
102 if (n > 1) {
103 CFMutableArrayRef sorted;
104
105 sorted = CFArrayCreateMutableCopy(NULL, 0, protocols);
106 CFArraySortValues(sorted,
107 CFRangeMake(0, n),
108 _SCNetworkProtocolCompare,
109 NULL);
110 CFRelease(protocols);
111 protocols = sorted;
112 }
113
114 allowIndex = FALSE;
115 }
116
117 // try to select the protocol by its protocol type
118
119 select_name = CFStringCreateWithCString(NULL, match, kCFStringEncodingUTF8);
120
121 n = CFArrayGetCount(protocols);
122 for (i = 0; i < n; i++) {
123 SCNetworkProtocolRef protocol;
124 CFStringRef type;
125
126 protocol = CFArrayGetValueAtIndex(protocols, i);
127 type = SCNetworkProtocolGetProtocolType(protocol);
128 if (CFStringCompare(select_name, type, kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
129 selected = protocol;
130 goto done;
131 }
132 }
133
134 if (allowIndex) {
135 char *end;
136 char *str = match;
137 long val;
138
139 // try to select the protocol by its index
140
141 errno = 0;
142 val = strtol(str, &end, 10);
143 if ((*str != '\0') && (*end == '\0') && (errno == 0)) {
144 if ((val > 0) && (val <= n)) {
145 selected = CFArrayGetValueAtIndex(protocols, val - 1);
146 }
147 }
148 }
149
150 if (selected != NULL) {
151 goto done;
152 }
153
154 SCPrint(TRUE, stdout, CFSTR("no match, which protocol?\n"));
155
156 done :
157
158 if (select_name != NULL) CFRelease(select_name);
159 return selected;
160 }
161
162
163 /* -------------------- */
164
165
166 __private_extern__
167 void
168 create_protocol(int argc, char **argv)
169 {
170 SCNetworkInterfaceRef interface;
171 CFStringRef protocolType;
172
173 if ((argc < 1) || (strlen(argv[0]) == 0)) {
174 SCPrint(TRUE, stdout, CFSTR("what protocol type?\n"));
175 return;
176 }
177
178 if (net_service == NULL) {
179 SCPrint(TRUE, stdout, CFSTR("network service not selected\n"));
180 return;
181 }
182
183 protocolType = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
184
185 interface = SCNetworkServiceGetInterface(net_service);
186 if (interface != NULL) {
187 CFArrayRef supported;
188 CFIndex i;
189 CFIndex n;
190
191 supported = SCNetworkInterfaceGetSupportedProtocolTypes(interface);
192 n = (supported != NULL) ? CFArrayGetCount(supported) : 0;
193 for (i = 0; i < n; i++) {
194 CFStringRef supportedType;
195
196 supportedType = CFArrayGetValueAtIndex(supported, i);
197 if (CFStringCompare(protocolType,
198 supportedType,
199 kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
200 CFRelease(protocolType);
201 protocolType = CFRetain(supportedType);
202 break;
203 }
204 }
205 }
206
207 if (!SCNetworkServiceAddProtocolType(net_service, protocolType)) {
208 SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
209 goto done;
210 }
211
212 _prefs_changed = TRUE;
213
214 if (protocols != NULL) {
215 CFRelease(protocols);
216 protocols = NULL;
217 }
218
219 if (net_protocol != NULL) CFRelease(net_protocol);
220 // net_protocol = NULL;
221
222 net_protocol = SCNetworkServiceCopyProtocol(net_service, protocolType);
223 if (net_protocol == NULL) {
224 SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
225 goto done;
226 }
227
228 SCPrint(TRUE, stdout,
229 CFSTR("protocol \"%@\" selected\n"),
230 protocolType);
231
232 done :
233
234 CFRelease(protocolType);
235 return;
236 }
237
238
239 /* -------------------- */
240
241
242 __private_extern__
243 void
244 disable_protocol(int argc, char **argv)
245 {
246 SCNetworkProtocolRef protocol = NULL;
247
248 if (argc > 0) {
249 protocol = _find_protocol(argv[0]);
250 } else {
251 if (net_protocol != NULL) {
252 protocol = net_protocol;
253 } else {
254 SCPrint(TRUE, stdout, CFSTR("protocol not selected\n"));
255 return;
256 }
257 }
258
259 if (protocol == NULL) {
260 return;
261 }
262
263 if (!SCNetworkProtocolSetEnabled(protocol, FALSE)) {
264 SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
265 return;
266 }
267
268 _prefs_changed = TRUE;
269
270 return;
271 }
272
273
274 /* -------------------- */
275
276
277 __private_extern__
278 void
279 enable_protocol(int argc, char **argv)
280 {
281 SCNetworkProtocolRef protocol = NULL;
282
283 if (argc > 0) {
284 protocol = _find_protocol(argv[0]);
285 } else {
286 if (net_protocol != NULL) {
287 protocol = net_protocol;
288 } else {
289 SCPrint(TRUE, stdout, CFSTR("protocol not selected\n"));
290 return;
291 }
292 }
293
294 if (protocol == NULL) {
295 return;
296 }
297
298 if (!SCNetworkProtocolSetEnabled(protocol, TRUE)) {
299 SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
300 return;
301 }
302
303 _prefs_changed = TRUE;
304
305 return;
306 }
307
308
309 /* -------------------- */
310
311
312 __private_extern__
313 void
314 remove_protocol(int argc, char **argv)
315 {
316 SCNetworkProtocolRef protocol = NULL;
317 CFStringRef protocolType;
318
319 if (argc > 0) {
320 protocol = _find_protocol(argv[0]);
321 } else {
322 if (net_protocol != NULL) {
323 protocol = net_protocol;
324 } else {
325 SCPrint(TRUE, stdout, CFSTR("protocol not selected\n"));
326 return;
327 }
328 }
329
330 if (protocol == NULL) {
331 return;
332 }
333
334 CFRetain(protocol);
335
336 protocolType = SCNetworkProtocolGetProtocolType(protocol);
337 if (!SCNetworkServiceRemoveProtocolType(net_service, protocolType)) {
338 SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
339 goto done;
340 }
341
342 _prefs_changed = TRUE;
343
344 SCPrint(TRUE, stdout,
345 CFSTR("protocol \"%@\" removed\n"),
346 protocolType);
347
348 if ((net_protocol != NULL) && CFEqual(protocol, net_protocol)) {
349 CFRelease(net_protocol);
350 net_protocol = NULL;
351 SCPrint(TRUE, stdout, CFSTR("& no protocol selected\n"));
352 }
353
354 if (protocols != NULL) {
355 CFRelease(protocols);
356 protocols = NULL;
357 }
358
359 done :
360
361 CFRelease(protocol);
362 return;
363 }
364
365
366 /* -------------------- */
367
368
369 __private_extern__
370 void
371 select_protocol(int argc, char **argv)
372 {
373 #pragma unused(argc)
374 SCNetworkProtocolRef protocol;
375
376 protocol = _find_protocol(argv[0]);
377
378 if (protocol == NULL) {
379 return;
380 }
381
382 if (net_protocol != NULL) CFRelease(net_protocol);
383 net_protocol = CFRetain(protocol);
384
385 SCPrint(TRUE, stdout,
386 CFSTR("protocol \"%@\" selected\n"),
387 SCNetworkProtocolGetProtocolType(protocol));
388
389 return;
390 }
391
392
393 #pragma mark -
394 #pragma mark DNS
395
396
397 static CF_RETURNS_RETAINED CFStringRef
398 __cleanupDomainName(CFStringRef domain)
399 {
400 CFMutableStringRef newDomain;
401
402 newDomain = CFStringCreateMutableCopy(NULL, 0, domain);
403 CFStringTrimWhitespace(newDomain);
404 CFStringTrim(newDomain, CFSTR("."));
405 if (CFStringGetLength(newDomain) == 0) {
406 CFRelease(newDomain);
407 newDomain = NULL;
408 }
409
410 return newDomain;
411 }
412
413
414 static int
415 __doDNSDomain(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
416 {
417 #pragma unused(description)
418 #pragma unused(info)
419 if (argc < 1) {
420 SCPrint(TRUE, stdout, CFSTR("DNS domain name not specified\n"));
421 return -1;
422 }
423
424 if (strlen(argv[0]) > 0) {
425 CFStringRef domain;
426 CFStringRef str;
427
428 str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
429 domain = __cleanupDomainName(str);
430 CFRelease(str);
431
432 if (domain != NULL) {
433 CFDictionarySetValue(newConfiguration, key, domain);
434 CFRelease(domain);
435 } else {
436 SCPrint(TRUE, stdout, CFSTR("invalid DNS domain name\n"));
437 return -1;
438 }
439 } else {
440 CFDictionaryRemoveValue(newConfiguration, key);
441 }
442
443 return 1;
444 }
445
446
447 static int
448 __doDNSDomainArray(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
449 {
450 #pragma unused(description)
451 #pragma unused(info)
452 CFMutableArrayRef domains;
453
454 if (argc < 1) {
455 SCPrint(TRUE, stdout, CFSTR("DNS search domain name(s) not specified\n"));
456 return -1;
457 }
458
459 domains = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
460
461 if (strlen(argv[0]) > 0) {
462 CFArrayRef array;
463 CFStringRef str;
464
465 str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
466 array = CFStringCreateArrayBySeparatingStrings(NULL, str, CFSTR(","));
467 CFRelease(str);
468
469 if (array != NULL) {
470 CFIndex i;
471 CFIndex n = CFArrayGetCount(array);
472
473 for (i = 0; i < n; i++) {
474 CFStringRef domain;
475
476 domain = __cleanupDomainName(CFArrayGetValueAtIndex(array, i));
477 if (domain != NULL) {
478 CFArrayAppendValue(domains, domain);
479 CFRelease(domain);
480 } else {
481 CFRelease(array);
482 CFRelease(domains);
483 SCPrint(TRUE, stdout, CFSTR("invalid DNS search domain name\n"));
484 return -1;
485 }
486 }
487 CFRelease(array);
488 }
489 }
490
491 if (CFArrayGetCount(domains) > 0) {
492 CFDictionarySetValue(newConfiguration, key, domains);
493 } else {
494 CFDictionaryRemoveValue(newConfiguration, key);
495 }
496
497 CFRelease(domains);
498 return 1;
499 }
500
501
502 static int
503 __doDNSServerAddresses(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
504 {
505 #pragma unused(description)
506 #pragma unused(info)
507 CFMutableArrayRef servers;
508
509 if (argc < 1) {
510 SCPrint(TRUE, stdout, CFSTR("DNS name server address(es) not specified\n"));
511 return -1;
512 }
513
514 servers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
515
516 if (strlen(argv[0]) > 0) {
517 CFArrayRef array;
518 CFIndex i;
519 CFIndex n;
520 CFStringRef str;
521
522 str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
523 array = CFStringCreateArrayBySeparatingStrings(NULL, str, CFSTR(","));
524 CFRelease(str);
525
526 n = (array != NULL) ? CFArrayGetCount(array) : 0;
527 for (i = 0; i < n; i++) {
528 char str[32];
529
530 if (_SC_cfstring_to_cstring(CFArrayGetValueAtIndex(array, i),
531 str,
532 sizeof(str),
533 kCFStringEncodingUTF8) != NULL) {
534 CFStringRef server;
535
536 server = __copyIPv4Address(str);
537 if (server == NULL) {
538 server = __copyIPv6Address(str);
539 }
540 if (server != NULL) {
541 CFArrayAppendValue(servers, server);
542 CFRelease(server);
543 continue;
544 }
545 }
546
547 SCPrint(TRUE, stdout, CFSTR("invalid DNS name server address\n"));
548 CFRelease(array);
549 CFRelease(servers);
550 return -1;
551 }
552 if (array != NULL) CFRelease(array);
553 }
554
555 if (CFArrayGetCount(servers) > 0) {
556 CFDictionarySetValue(newConfiguration, key, servers);
557 } else {
558 CFDictionaryRemoveValue(newConfiguration, key);
559 }
560
561 CFRelease(servers);
562 return 1;
563 }
564
565
566 static options dnsOptions[] = {
567 { "DomainName" , "domain" , isOther, &kSCPropNetDNSDomainName , __doDNSDomain , NULL },
568 { "domain" , "domain" , isOther, &kSCPropNetDNSDomainName , __doDNSDomain , NULL },
569 { "SearchDomains" , "search" , isOther, &kSCPropNetDNSSearchDomains , __doDNSDomainArray , NULL },
570 { "search" , "search" , isOther, &kSCPropNetDNSSearchDomains , __doDNSDomainArray , NULL },
571 { "ServerAddresses", "address", isOther, &kSCPropNetDNSServerAddresses, __doDNSServerAddresses, NULL },
572 { "nameserver" , "address", isOther, &kSCPropNetDNSServerAddresses, __doDNSServerAddresses, NULL },
573 { "nameservers" , "address", isOther, &kSCPropNetDNSServerAddresses, __doDNSServerAddresses, NULL },
574 { "SupplementalMatchDomains",
575 "domain",
576 isOther,
577 &kSCPropNetDNSSupplementalMatchDomains,
578 __doDNSDomainArray,
579 NULL },
580
581 { "?" , NULL , isHelp , NULL , NULL,
582 "\nDNS configuration commands\n\n"
583 " set protocol search domain-name[,domain-name-2]\n"
584 " set protocol nameserver x1.x1.x1.x1[,x2.x2.x2.x2]\n"
585 }
586 };
587 #define N_DNS_OPTIONS (sizeof(dnsOptions) / sizeof(dnsOptions[0]))
588
589
590 static Boolean
591 set_protocol_dns(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
592 {
593 Boolean ok;
594
595 ok = _process_options(dnsOptions, N_DNS_OPTIONS, argc, argv, newConfiguration);
596 return ok;
597 }
598
599
600 #pragma mark -
601 #pragma mark IPv4
602
603
604 #define allowIPv4Address 1<<1 // allow address
605 #define allowIPv4Netmask 1<<2 // allow subnet mask
606 #define allowIPv4Router 1<<3 // allow router
607 #define allowIPv4DHCPClientID 1<<4 // allow DCHP Client ID
608
609 static selections ipv4ConfigMethods[] = {
610 { CFSTR("BOOTP") , &kSCValNetIPv4ConfigMethodBOOTP , 0 },
611 { CFSTR("DHCP") , &kSCValNetIPv4ConfigMethodDHCP , allowIPv4DHCPClientID },
612 { CFSTR("INFORM") , &kSCValNetIPv4ConfigMethodINFORM , allowIPv4Address },
613 { CFSTR("LinkLocal"), &kSCValNetIPv4ConfigMethodLinkLocal, 0 },
614 { CFSTR("Manual") , &kSCValNetIPv4ConfigMethodManual , allowIPv4Address|allowIPv4Netmask|allowIPv4Router },
615 { CFSTR("PPP") , &kSCValNetIPv4ConfigMethodPPP , allowIPv4Address|selectionNotAvailable },
616 { NULL , NULL , 0 }
617 };
618
619
620 static int
621 __doIPv4ConfigMethod(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
622 {
623 #pragma unused(description)
624 #pragma unused(info)
625 #pragma unused(argc)
626 #pragma unused(argv)
627 unsigned int flags;
628 CFStringRef method;
629 CFIndex methodIndex;
630
631 method = CFDictionaryGetValue(newConfiguration, key);
632 methodIndex = _find_selection(method, (selections *)ipv4ConfigMethods, &flags);
633 if (methodIndex != kCFNotFound) {
634 if (!(flags & allowIPv4Address)) {
635 CFDictionaryRemoveValue(newConfiguration, kSCPropNetIPv4Addresses);
636 }
637 if (!(flags & allowIPv4Netmask)) {
638 CFDictionaryRemoveValue(newConfiguration, kSCPropNetIPv4SubnetMasks);
639 }
640 if (!(flags & allowIPv4Router)) {
641 CFDictionaryRemoveValue(newConfiguration, kSCPropNetIPv4Router);
642 }
643 if (!(flags & allowIPv4DHCPClientID)) {
644 CFDictionaryRemoveValue(newConfiguration, kSCPropNetIPv4DHCPClientID);
645 }
646 } else {
647 SCPrint(TRUE, stdout, CFSTR("unknown configuration method\n"));
648 return -1;
649 }
650
651 return 0;
652 }
653
654
655 static int
656 __doIPv4Addresses(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
657 {
658 #pragma unused(description)
659 #pragma unused(argc)
660 Boolean useArray = (info == (void *)FALSE) ? FALSE : TRUE;
661
662 if (strlen(argv[0]) > 0) {
663 CFStringRef address;
664
665 address = __copyIPv4Address(argv[0]);
666 if (address != NULL) {
667 if (useArray) {
668 CFArrayRef addresses;
669
670 addresses = CFArrayCreate(NULL, (const void **)&address, 1, &kCFTypeArrayCallBacks);
671 CFDictionarySetValue(newConfiguration, key, addresses);
672 CFRelease(addresses);
673 } else {
674 CFDictionarySetValue(newConfiguration, key, address);
675 }
676 CFRelease(address);
677 } else {
678 return -1;
679 }
680 } else {
681 CFDictionaryRemoveValue(newConfiguration, key);
682 }
683
684 return 1;
685 }
686
687
688 static options ipv4Options[] = {
689 { "ConfigMethod", "configuration method"
690 , isChooseOne , &kSCPropNetIPv4ConfigMethod, __doIPv4ConfigMethod, (void *)ipv4ConfigMethods },
691 { "config" , "configuration method"
692 , isChooseOne , &kSCPropNetIPv4ConfigMethod, __doIPv4ConfigMethod, (void *)ipv4ConfigMethods },
693 { "Addresses" , "address" , isOther , &kSCPropNetIPv4Addresses , __doIPv4Addresses , (void *)TRUE },
694 { "address" , "address" , isOther , &kSCPropNetIPv4Addresses , __doIPv4Addresses , (void *)TRUE },
695 { "SubnetMasks" , "netmask" , isOther , &kSCPropNetIPv4SubnetMasks , __doIPv4Addresses , (void *)TRUE },
696 { "netmask" , "netmask" , isOther , &kSCPropNetIPv4SubnetMasks , __doIPv4Addresses , (void *)TRUE },
697 { "Router" , "address" , isOther , &kSCPropNetIPv4Router , __doIPv4Addresses , (void *)FALSE },
698 { "DHCPClientID", "client ID", isString , &kSCPropNetIPv4DHCPClientID, NULL , NULL },
699
700 { "?" , NULL , isHelp , NULL , NULL ,
701 "\nIPv4 configuration commands\n\n"
702 " set protocol config {BOOTP|DHCP|INFORM|MANUAL}\n"
703 "\n w/config=BOOTP\n"
704 " None\n"
705 "\n w/config=DHCP\n"
706 " set protocol dhcpclientid identifier\n"
707 "\n w/config=INFORM\n"
708 " set protocol address x.x.x.x\n"
709 "\n w/config=MANUAL\n"
710 " set protocol address x.x.x.x\n"
711 " set protocol netmask x.x.x.x\n"
712 " set protocol router x.x.x.x\n"
713 }
714 };
715 #define N_IPV4_OPTIONS (sizeof(ipv4Options) / sizeof(ipv4Options[0]))
716
717
718 static Boolean
719 set_protocol_ipv4(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
720 {
721 Boolean ok;
722
723 ok = _process_options(ipv4Options, N_IPV4_OPTIONS, argc, argv, newConfiguration);
724 if (ok) {
725 unsigned int flags;
726 CFStringRef method;
727 CFIndex methodIndex;
728
729 // validate configuration
730 method = CFDictionaryGetValue(newConfiguration, kSCPropNetIPv4ConfigMethod);
731 methodIndex = _find_selection(method, (selections *)ipv4ConfigMethods, &flags);
732 if (methodIndex == kCFNotFound) {
733 SCPrint(TRUE, stdout, CFSTR("unknown configuration method\n"));
734 return FALSE;
735 }
736
737 if (!(flags & allowIPv4Address) && CFDictionaryContainsKey(newConfiguration, kSCPropNetIPv4Addresses)) {
738 SCPrint(TRUE, stdout,
739 CFSTR("IP address not allowed with %@ configuration\n"),
740 ipv4ConfigMethods[methodIndex].selection);
741 return FALSE;
742 }
743
744 if (!(flags & allowIPv4Netmask) && CFDictionaryContainsKey(newConfiguration, kSCPropNetIPv4SubnetMasks)) {
745 SCPrint(TRUE, stdout,
746 CFSTR("Subnet mask not allowed with %@ configuration\n"),
747 ipv4ConfigMethods[methodIndex].selection);
748 return FALSE;
749 }
750
751 if (!(flags & allowIPv4Router) && CFDictionaryContainsKey(newConfiguration, kSCPropNetIPv4Router)) {
752 SCPrint(TRUE, stdout,
753 CFSTR("Default route not allowed with %@ configuration\n"),
754 ipv4ConfigMethods[methodIndex].selection);
755 return FALSE;
756 }
757
758 if (!(flags & allowIPv4DHCPClientID) && CFDictionaryContainsKey(newConfiguration, kSCPropNetIPv4DHCPClientID)) {
759 SCPrint(TRUE, stdout,
760 CFSTR("DHCP client ID not allowed with %@ configuration\n"),
761 ipv4ConfigMethods[methodIndex].selection);
762 return FALSE;
763 }
764 }
765
766 return ok;
767 }
768
769
770 #pragma mark -
771 #pragma mark IPv6
772
773
774 #define allowIPv6Address 1<<1 // allow address
775 #define allowIPv6PrefixLength 1<<2 // allow prefix length
776 #define allowIPv6Router 1<<3 // allow router
777
778 static selections ipv6ConfigMethods[] = {
779 { CFSTR("Automatic") , & kSCValNetIPv6ConfigMethodAutomatic , 0 },
780 { CFSTR("Manual") , & kSCValNetIPv6ConfigMethodManual , allowIPv6Address|allowIPv6PrefixLength|allowIPv6Router },
781 { CFSTR("RouterAdvertisement"), & kSCValNetIPv6ConfigMethodRouterAdvertisement, allowIPv6Address },
782 { CFSTR("6to4") , & kSCValNetIPv6ConfigMethod6to4 , 0 },
783 { NULL , NULL , 0 }
784 };
785
786
787 static int
788 __doIPv6ConfigMethod(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
789 {
790 #pragma unused(description)
791 #pragma unused(info)
792 #pragma unused(argc)
793 #pragma unused(argv)
794 unsigned int flags;
795 CFStringRef method;
796 CFIndex methodIndex;
797
798 method = CFDictionaryGetValue(newConfiguration, key);
799 methodIndex = _find_selection(method, (selections *)ipv6ConfigMethods, &flags);
800 if (methodIndex != kCFNotFound) {
801 if (!(flags & allowIPv6Address)) {
802 CFDictionaryRemoveValue(newConfiguration, kSCPropNetIPv6Addresses);
803 }
804 if (!(flags & allowIPv6PrefixLength)) {
805 CFDictionaryRemoveValue(newConfiguration, kSCPropNetIPv6PrefixLength);
806 }
807 if (!(flags & allowIPv6Router)) {
808 CFDictionaryRemoveValue(newConfiguration, kSCPropNetIPv6Router);
809 }
810 } else {
811 SCPrint(TRUE, stdout, CFSTR("unknown configuration method\n"));
812 return -1;
813 }
814
815 return 0;
816 }
817
818
819 static int
820 __doIPv6Addresses(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
821 {
822 #pragma unused(description)
823 #pragma unused(argc)
824 Boolean useArray = (info == (void *)FALSE) ? FALSE : TRUE;
825
826 if (strlen(argv[0]) > 0) {
827 CFStringRef address;
828
829 address = __copyIPv6Address(argv[0]);
830 if (address != NULL) {
831 if (useArray) {
832 CFArrayRef addresses;
833
834 addresses = CFArrayCreate(NULL, (const void **)&address, 1, &kCFTypeArrayCallBacks);
835 CFDictionarySetValue(newConfiguration, key, addresses);
836 CFRelease(addresses);
837 } else {
838 CFDictionarySetValue(newConfiguration, key, address);
839 }
840 CFRelease(address);
841 } else {
842 return -1;
843 }
844 } else {
845 CFDictionaryRemoveValue(newConfiguration, key);
846 }
847
848 return 1;
849 }
850
851 static int
852 __doIPv6PrefixLength(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
853 {
854 #pragma unused(description)
855 #pragma unused(argc)
856 #pragma unused(info)
857 char * prefix = argv[0];
858 if (*prefix != '\0') {
859 char *end;
860 int prefixLength;
861
862 prefixLength = (int)strtol(prefix, &end, 10);
863 errno = 0;
864 if (*end == '\0' && errno == 0 && prefixLength > 0 && prefixLength <= 128) {
865 CFArrayRef prefixes;
866 CFNumberRef num;
867
868 num = CFNumberCreate(NULL, kCFNumberIntType, &prefixLength);
869 prefixes = CFArrayCreate(NULL, (const void **)&num, 1, &kCFTypeArrayCallBacks);
870 CFRelease(num);
871 CFDictionarySetValue(newConfiguration, key, prefixes);
872 CFRelease(prefixes);
873 } else {
874 SCPrint(TRUE, stdout, CFSTR("Invalid prefix length '%s' (valid range 1..128)\n"), prefix);
875 return -1;
876 }
877 } else {
878 CFDictionaryRemoveValue(newConfiguration, key);
879 }
880
881 return 1;
882 }
883
884
885 static options ipv6Options[] = {
886 { "ConfigMethod", "configuration method"
887 , isChooseOne, &kSCPropNetIPv6ConfigMethod, __doIPv6ConfigMethod, (void *)ipv6ConfigMethods },
888 { "config" , "configuration method"
889 , isChooseOne, &kSCPropNetIPv6ConfigMethod, __doIPv6ConfigMethod, (void *)ipv6ConfigMethods },
890 { "Addresses" , "address" , isOther , &kSCPropNetIPv6Addresses , __doIPv6Addresses , (void *)TRUE },
891 { "address" , "address" , isOther , &kSCPropNetIPv6Addresses , __doIPv6Addresses , (void *)TRUE },
892 { "EnableCGA" , NULL , isBoolean , &kSCPropNetIPv6EnableCGA , NULL , NULL },
893 { "PrefixLength", "prefix length", isOther , &kSCPropNetIPv6PrefixLength, __doIPv6PrefixLength, NULL },
894 { "Router" , "address" , isOther , &kSCPropNetIPv6Router , __doIPv6Addresses , (void *)FALSE },
895
896 { "?" , NULL , isHelp , NULL , NULL ,
897 "\nIPv6 configuration commands\n\n"
898 " set protocol config {Automatic|MANUAL}\n"
899 "\n w/config=Automatic\n"
900 " None\n"
901 "\n w/config=MANUAL\n"
902 " set protocol address x:x:x:x:x:x\n"
903 " set protocol router x:x:x:x:x:x\n"
904 " set protocol prefixlength n\n"
905 }
906 };
907 #define N_IPV6_OPTIONS (sizeof(ipv6Options) / sizeof(ipv6Options[0]))
908
909
910 static Boolean
911 set_protocol_ipv6(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
912 {
913 Boolean ok;
914
915 ok = _process_options(ipv6Options, N_IPV6_OPTIONS, argc, argv, newConfiguration);
916 if (ok) {
917 unsigned int flags;
918 CFStringRef method;
919 CFIndex methodIndex;
920
921 // validate configuration
922 method = CFDictionaryGetValue(newConfiguration, kSCPropNetIPv6ConfigMethod);
923 methodIndex = _find_selection(method, (selections *)ipv6ConfigMethods, &flags);
924 if (methodIndex == kCFNotFound) {
925 SCPrint(TRUE, stdout, CFSTR("unknown configuration method\n"));
926 return FALSE;
927 }
928
929 if (!(flags & allowIPv6Address) && CFDictionaryContainsKey(newConfiguration, kSCPropNetIPv6Addresses)) {
930 SCPrint(TRUE, stdout,
931 CFSTR("IP address not allowed with %@ configuration\n"),
932 ipv6ConfigMethods[methodIndex].selection);
933 return FALSE;
934 }
935
936 if (!(flags & allowIPv6PrefixLength) && CFDictionaryContainsKey(newConfiguration, kSCPropNetIPv6PrefixLength)) {
937 SCPrint(TRUE, stdout,
938 CFSTR("Prefix length not allowed with %@ configuration\n"),
939 ipv6ConfigMethods[methodIndex].selection);
940 return FALSE;
941 }
942
943 if (!(flags & allowIPv6Router) && CFDictionaryContainsKey(newConfiguration, kSCPropNetIPv6Router)) {
944 SCPrint(TRUE, stdout,
945 CFSTR("Router not allowed with %@ configuration\n"),
946 ipv6ConfigMethods[methodIndex].selection);
947 return FALSE;
948 }
949 }
950
951 return ok;
952 }
953
954
955 #pragma mark -
956 #pragma mark Proxies
957
958
959 typedef const struct {
960 const char *proxy;
961 const CFStringRef *keyEnable;
962 const CFStringRef *keyProxy;
963 const CFStringRef *keyPort;
964 const CFStringRef *keyURL;
965 } proxyKeys;
966
967 static proxyKeys proxyKeys_FTP = { "FTP" , &kSCPropNetProxiesFTPEnable , &kSCPropNetProxiesFTPProxy , &kSCPropNetProxiesFTPPort , NULL };
968 static proxyKeys proxyKeys_Gopher = { "Gopher", &kSCPropNetProxiesGopherEnable , &kSCPropNetProxiesGopherProxy, &kSCPropNetProxiesGopherPort, NULL };
969 static proxyKeys proxyKeys_HTTP = { "HTTP" , &kSCPropNetProxiesHTTPEnable , &kSCPropNetProxiesHTTPProxy , &kSCPropNetProxiesHTTPPort , NULL };
970 static proxyKeys proxyKeys_HTTPS = { "HTTPS" , &kSCPropNetProxiesHTTPSEnable , &kSCPropNetProxiesHTTPSProxy , &kSCPropNetProxiesHTTPSPort , NULL };
971 static proxyKeys proxyKeys_RTSP = { "RTSP" , &kSCPropNetProxiesRTSPEnable , &kSCPropNetProxiesRTSPProxy , &kSCPropNetProxiesRTSPPort , NULL };
972 static proxyKeys proxyKeys_SOCKS = { "SOCKS" , &kSCPropNetProxiesSOCKSEnable , &kSCPropNetProxiesSOCKSProxy , &kSCPropNetProxiesSOCKSPort , NULL };
973 static proxyKeys proxyKeys_PAC = { ".pac" , &kSCPropNetProxiesProxyAutoConfigEnable , NULL , NULL , &kSCPropNetProxiesProxyAutoConfigURLString };
974 static proxyKeys proxyKeys_WPAD = { "WPAD" , &kSCPropNetProxiesProxyAutoDiscoveryEnable, NULL , NULL , NULL };
975
976 static proxyKeys *currentProxy = NULL;
977
978
979 static int __doProxySelect (CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration);
980 static int __doProxyEnable (CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration);
981 static int __doProxyHost (CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration);
982 static int __doProxyPort (CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration);
983 static int __doProxyURL (CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration);
984 static int __doProxyFTPPassive(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration);
985
986
987 static options proxyOptions[] = {
988 // general options
989 { "ExceptionsList" , "exceptions", isStringArray, &kSCPropNetProxiesExceptionsList , NULL , NULL },
990 { "ExcludeSimpleHostnames", NULL , isBoolean , &kSCPropNetProxiesExcludeSimpleHostnames, NULL , NULL },
991 // proxy selection
992 { "FTP" , NULL , isOther , NULL , __doProxySelect , (void *)&proxyKeys_FTP },
993 { "Gopher" , NULL , isOther , NULL , __doProxySelect , (void *)&proxyKeys_Gopher },
994 { "HTTP" , NULL , isOther , NULL , __doProxySelect , (void *)&proxyKeys_HTTP },
995 { "HTTPS" , NULL , isOther , NULL , __doProxySelect , (void *)&proxyKeys_HTTPS },
996 { "RTSP" , NULL , isOther , NULL , __doProxySelect , (void *)&proxyKeys_RTSP },
997 { "SOCKS" , NULL , isOther , NULL , __doProxySelect , (void *)&proxyKeys_SOCKS },
998 { "ProxyAutoConfig" , NULL , isOther , NULL , __doProxySelect , (void *)&proxyKeys_PAC },
999 { ".pac" , NULL , isOther , NULL , __doProxySelect , (void *)&proxyKeys_PAC },
1000 { "ProxyAutoDiscovery" , NULL , isOther , NULL , __doProxySelect , (void *)&proxyKeys_WPAD },
1001 { "WPAD" , NULL , isOther , NULL , __doProxySelect , (void *)&proxyKeys_WPAD },
1002 // proxy modifiers
1003 { "disable" , NULL , isOther , NULL , __doProxyEnable , (void *)FALSE },
1004 { "enable" , NULL , isOther , NULL , __doProxyEnable , (void *)TRUE },
1005 { "proxy" , NULL , isOther , NULL , __doProxyHost , NULL },
1006 { "host" , NULL , isOther , NULL , __doProxyHost , NULL },
1007 { "port" , NULL , isOther , NULL , __doProxyPort , NULL },
1008 { "url" , NULL , isOther , NULL , __doProxyURL , NULL },
1009 // (ftp) proxy modifiers
1010 { "FTPPassive" , NULL , isBoolean , &kSCPropNetProxiesFTPPassive , __doProxyFTPPassive, NULL },
1011 { "passive" , NULL , isBoolean , &kSCPropNetProxiesFTPPassive , __doProxyFTPPassive, NULL },
1012 // help
1013 { "?" , NULL , isHelp , NULL , NULL ,
1014 "\nProxy configuration commands\n\n"
1015 " set protocol ExceptionsList exception[,exception-2]\n"
1016 " set protocol ExcludeSimpleHostnames {enable|disable}\n"
1017 "\n"
1018 " set protocol ftp {enable|disable}\n"
1019 " set protocol ftp host proxy-host\n"
1020 " set protocol ftp port proxy-port\n"
1021 " set protocol ftp passive {enable|disable}\n"
1022 "\n"
1023 " set protocol http {enable|disable}\n"
1024 " set protocol http host proxy-host\n"
1025 " set protocol http port proxy-port\n"
1026 "\n"
1027 " set protocol https {enable|disable}\n"
1028 " set protocol https host proxy-host\n"
1029 " set protocol https port proxy-port\n"
1030 "\n"
1031 " set protocol rtsp {enable|disable}\n"
1032 " set protocol rtsp host proxy-host\n"
1033 " set protocol rtsp port proxy-port\n"
1034 "\n"
1035 " set protocol socks {enable|disable}\n"
1036 " set protocol socks host proxy-host\n"
1037 " set protocol socks port proxy-port\n"
1038 "\n"
1039 " set protocol .pac {enable|disable}\n"
1040 " set protocol .pac url .pac-url\n"
1041 "\n"
1042 " set protocol wpad {enable|disable}\n"
1043 }
1044 };
1045 #define N_PROXY_OPTIONS (sizeof(proxyOptions) / sizeof(proxyOptions[0]))
1046
1047
1048 static int
1049 __doProxySelect(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1050 {
1051 #pragma unused(key)
1052 #pragma unused(description)
1053 #pragma unused(newConfiguration)
1054 CFIndex nextOption;
1055
1056 if (argc < 1) {
1057 SCPrint(TRUE, stdout, CFSTR("proxy option[s] not specified\n"));
1058 return -1;
1059 }
1060
1061 currentProxy = (proxyKeys *)info;
1062
1063 nextOption = _find_option(argv[0], proxyOptions, N_PROXY_OPTIONS);
1064 if ((nextOption == kCFNotFound) ||
1065 (proxyOptions[nextOption].handler == __doProxySelect)) {
1066 SCPrint(TRUE, stdout, CFSTR("%s proxy option[s] not specified\n"), currentProxy->proxy);
1067 return -1;
1068 }
1069
1070 return 0;
1071 }
1072
1073
1074 static int
1075 __doProxyEnable(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1076 {
1077 #pragma unused(key)
1078 #pragma unused(description)
1079 #pragma unused(argc)
1080 #pragma unused(argv)
1081 Boolean enabled = (info == (void *)FALSE) ? FALSE : TRUE;
1082
1083 if (currentProxy == NULL) {
1084 SCPrint(TRUE, stdout, CFSTR("proxy not specified\n"));
1085 return -1;
1086 }
1087
1088 if (currentProxy->keyEnable == NULL) {
1089 SCPrint(TRUE, stdout, CFSTR("%s proxy cannot be %s\n"),
1090 currentProxy->proxy,
1091 enabled ? "enabled" : "disabled");
1092 return -1;
1093 }
1094
1095
1096 if (enabled) {
1097 CFDictionarySetValue(newConfiguration, *(currentProxy->keyEnable), CFNumberRef_1);
1098 } else {
1099 CFDictionaryRemoveValue(newConfiguration, *(currentProxy->keyEnable));
1100
1101 if (currentProxy->keyProxy != NULL) {
1102 CFDictionaryRemoveValue(newConfiguration, *(currentProxy->keyProxy));
1103 }
1104
1105 if (currentProxy->keyPort != NULL) {
1106 CFDictionaryRemoveValue(newConfiguration, *(currentProxy->keyPort));
1107 }
1108
1109 if (currentProxy->keyURL != NULL) {
1110 CFDictionaryRemoveValue(newConfiguration, *(currentProxy->keyURL));
1111 }
1112 }
1113
1114 return 0;
1115 }
1116
1117
1118 static Boolean
1119 __proxy_enabled(CFDictionaryRef configuration, const CFStringRef *enableKey)
1120 {
1121 CFNumberRef num;
1122 int val;
1123
1124 if (enableKey == NULL) {
1125 return TRUE; // if proxy does not need to be enabled
1126 }
1127
1128 num = CFDictionaryGetValue(configuration, *enableKey);
1129 if (!isA_CFNumber(num) ||
1130 !CFNumberGetValue(num, kCFNumberIntType, &val) ||
1131 (val == 0)) {
1132 return FALSE; // if not enabled
1133 }
1134
1135 return TRUE;
1136 }
1137
1138
1139 static int
1140 __doProxyHost(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1141 {
1142 #pragma unused(key)
1143 #pragma unused(description)
1144 #pragma unused(info)
1145 if (currentProxy == NULL) {
1146 SCPrint(TRUE, stdout, CFSTR("proxy not specified\n"));
1147 return -1;
1148 }
1149
1150 if (currentProxy->keyProxy == NULL) {
1151 SCPrint(TRUE, stdout, CFSTR("%s proxy host cannot be specified\n"), currentProxy->proxy);
1152 return -1;
1153 }
1154
1155 if (!__proxy_enabled(newConfiguration, currentProxy->keyEnable)) {
1156 SCPrint(TRUE, stdout, CFSTR("%s proxy not enabled\n"), currentProxy->proxy);
1157 return -1;
1158 }
1159
1160 if (argc < 1) {
1161 SCPrint(TRUE, stdout, CFSTR("%s proxy host not specified\n"), currentProxy->proxy);
1162 return -1;
1163 }
1164
1165 if (strlen(argv[0]) > 0) {
1166 CFStringRef host;
1167
1168 host = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
1169 CFDictionarySetValue(newConfiguration, *(currentProxy->keyProxy), host);
1170 CFRelease(host);
1171 } else {
1172 CFDictionaryRemoveValue(newConfiguration, *(currentProxy->keyProxy));
1173 }
1174
1175 return 1;
1176 }
1177
1178
1179 static int
1180 __doProxyPort(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1181 {
1182 #pragma unused(key)
1183 #pragma unused(description)
1184 #pragma unused(info)
1185 if (currentProxy == NULL) {
1186 SCPrint(TRUE, stdout, CFSTR("proxy not specified\n"));
1187 return -1;
1188 }
1189
1190 if (currentProxy->keyPort == NULL) {
1191 SCPrint(TRUE, stdout, CFSTR("%s proxy port cannot be specified\n"), currentProxy->proxy);
1192 return -1;
1193 }
1194
1195 if (!__proxy_enabled(newConfiguration, currentProxy->keyEnable)) {
1196 SCPrint(TRUE, stdout, CFSTR("%s proxy not enabled\n"), currentProxy->proxy);
1197 return -1;
1198 }
1199
1200 if (argc < 1) {
1201 SCPrint(TRUE, stdout, CFSTR("%s proxy port not specified\n"), currentProxy->proxy);
1202 return -1;
1203 }
1204
1205 if (strlen(argv[0]) > 0) {
1206 CFNumberRef num;
1207 int port;
1208
1209 num = _copy_number(argv[0]);
1210 if (!isA_CFNumber(num) ||
1211 !CFNumberGetValue(num, kCFNumberIntType, &port) ||
1212 (port < 0) || (port > 65535)) {
1213 SCPrint(TRUE, stdout, CFSTR("invalid %s proxy port number\n"), currentProxy->proxy);
1214 if (num != NULL) CFRelease(num);
1215 return -1;
1216 }
1217
1218 CFDictionarySetValue(newConfiguration, *(currentProxy->keyPort), num);
1219 CFRelease(num);
1220 } else {
1221 CFDictionaryRemoveValue(newConfiguration, *(currentProxy->keyPort));
1222 }
1223
1224 return 1;
1225 }
1226
1227
1228 static int
1229 __doProxyURL(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1230 {
1231 #pragma unused(key)
1232 #pragma unused(description)
1233 #pragma unused(info)
1234 if (currentProxy == NULL) {
1235 SCPrint(TRUE, stdout, CFSTR("proxy not specified\n"));
1236 return -1;
1237 }
1238
1239 if (currentProxy->keyURL == NULL) {
1240 SCPrint(TRUE, stdout, CFSTR("%s proxy URL cannot be specified\n"), currentProxy->proxy);
1241 return -1;
1242 }
1243
1244 if (!__proxy_enabled(newConfiguration, currentProxy->keyEnable)) {
1245 SCPrint(TRUE, stdout, CFSTR("%s proxy not enabled\n"), currentProxy->proxy);
1246 return -1;
1247 }
1248
1249 if (argc < 1) {
1250 SCPrint(TRUE, stdout, CFSTR("%s proxy URL not specified\n"), currentProxy->proxy);
1251 return -1;
1252 }
1253
1254 if (strlen(argv[0]) > 0) {
1255 CFStringRef url;
1256
1257 url = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
1258 CFDictionarySetValue(newConfiguration, *(currentProxy->keyURL), url);
1259 CFRelease(url);
1260 } else {
1261 CFDictionaryRemoveValue(newConfiguration, *(currentProxy->keyURL));
1262 }
1263
1264 return 1;
1265 }
1266
1267
1268 static int
1269 __doProxyFTPPassive(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1270 {
1271 #pragma unused(key)
1272 #pragma unused(description)
1273 #pragma unused(info)
1274 #pragma unused(argc)
1275 #pragma unused(argv)
1276 #pragma unused(newConfiguration)
1277 if (currentProxy == NULL) {
1278 SCPrint(TRUE, stdout, CFSTR("proxy not specified\n"));
1279 return -1;
1280 }
1281
1282 if (currentProxy != &proxyKeys_FTP) {
1283 SCPrint(TRUE, stdout, CFSTR("passive can only be enable for FTP proxy\n"));
1284 return -1;
1285 }
1286
1287 return 0;
1288 }
1289
1290
1291 static Boolean
1292 set_protocol_proxies(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1293 {
1294 Boolean ok;
1295
1296 ok = _process_options(proxyOptions, N_PROXY_OPTIONS, argc, argv, newConfiguration);
1297 return ok;
1298 }
1299
1300
1301 #pragma mark -
1302 #pragma mark SMB
1303
1304
1305 #if !TARGET_OS_IPHONE
1306
1307
1308 static CF_RETURNS_RETAINED CFStringRef
1309 __cleanupName(CFStringRef name)
1310 {
1311 CFMutableStringRef newName;
1312
1313 newName = CFStringCreateMutableCopy(NULL, 0, name);
1314 CFStringTrimWhitespace(newName);
1315 if (CFStringGetLength(newName) == 0) {
1316 CFRelease(newName);
1317 newName = NULL;
1318 }
1319
1320 return newName;
1321 }
1322
1323
1324 static int
1325 __doSMBName(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1326 {
1327 #pragma unused(description)
1328 #pragma unused(info)
1329 if (argc < 1) {
1330 SCPrint(TRUE, stdout, CFSTR("NetBIOS name not specified\n"));
1331 return -1;
1332 }
1333
1334 if (strlen(argv[0]) > 0) {
1335 CFStringRef name;
1336 CFStringRef str;
1337
1338 str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
1339 name = __cleanupName(str);
1340 CFRelease(str);
1341
1342 if (name != NULL) {
1343 CFDictionarySetValue(newConfiguration, key, name);
1344 CFRelease(name);
1345 } else {
1346 SCPrint(TRUE, stdout, CFSTR("invalid NetBIOS name\n"));
1347 return -1;
1348 }
1349 } else {
1350 CFDictionaryRemoveValue(newConfiguration, key);
1351 }
1352
1353 return 1;
1354 }
1355
1356
1357 static int
1358 __doSMBWorkgroup(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1359 {
1360 #pragma unused(description)
1361 #pragma unused(info)
1362 if (argc < 1) {
1363 SCPrint(TRUE, stdout, CFSTR("Workgroup not specified\n"));
1364 return -1;
1365 }
1366
1367 if (strlen(argv[0]) > 0) {
1368 CFStringRef name;
1369 CFStringRef str;
1370
1371 str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
1372 name = __cleanupName(str);
1373 CFRelease(str);
1374
1375 if (name != NULL) {
1376 CFDictionarySetValue(newConfiguration, key, name);
1377 CFRelease(name);
1378 } else {
1379 SCPrint(TRUE, stdout, CFSTR("invalid Workgroup\n"));
1380 return -1;
1381 }
1382 } else {
1383 CFDictionaryRemoveValue(newConfiguration, key);
1384 }
1385
1386 return 1;
1387 }
1388
1389
1390 static int
1391 __doSMBWINSAddresses(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1392 {
1393 #pragma unused(description)
1394 #pragma unused(info)
1395 CFMutableArrayRef servers;
1396
1397 if (argc < 1) {
1398 SCPrint(TRUE, stdout, CFSTR("WINS address(es) not specified\n"));
1399 return -1;
1400 }
1401
1402 servers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1403
1404 if (strlen(argv[0]) > 0) {
1405 CFArrayRef array;
1406 CFIndex i;
1407 CFIndex n;
1408 CFStringRef str;
1409
1410 str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
1411 array = CFStringCreateArrayBySeparatingStrings(NULL, str, CFSTR(","));
1412 CFRelease(str);
1413
1414 n = (array != NULL) ? CFArrayGetCount(array) : 0;
1415 for (i = 0; i < n; i++) {
1416 char str[32];
1417
1418 if (_SC_cfstring_to_cstring(CFArrayGetValueAtIndex(array, i),
1419 str,
1420 sizeof(str),
1421 kCFStringEncodingUTF8) != NULL) {
1422 CFStringRef server;
1423
1424 server = __copyIPv4Address(str);
1425 //if (server == NULL) {
1426 // server = __copyIPv6Address(str);
1427 //}
1428 if (server != NULL) {
1429 CFArrayAppendValue(servers, server);
1430 CFRelease(server);
1431 continue;
1432 }
1433 }
1434
1435 SCPrint(TRUE, stdout, CFSTR("invalid WINS address\n"));
1436 CFRelease(array);
1437 CFRelease(servers);
1438 return -1;
1439 }
1440 if (array != NULL) CFRelease(array);
1441 }
1442
1443 if (CFArrayGetCount(servers) > 0) {
1444 CFDictionarySetValue(newConfiguration, key, servers);
1445 } else {
1446 CFDictionaryRemoveValue(newConfiguration, key);
1447 }
1448
1449 CFRelease(servers);
1450 return 1;
1451 }
1452
1453
1454 static selections smbNodeTypes[] = {
1455 { CFSTR("Broadcast"), &kSCValNetSMBNetBIOSNodeTypeBroadcast, 0 },
1456 { CFSTR("Peer") , &kSCValNetSMBNetBIOSNodeTypePeer , 0 },
1457 { CFSTR("Mixed") , &kSCValNetSMBNetBIOSNodeTypeMixed , 0 },
1458 { CFSTR("Hybrid") , &kSCValNetSMBNetBIOSNodeTypeHybrid , 0 },
1459 { NULL , NULL , 0 }
1460 };
1461
1462
1463 static options smbOptions[] = {
1464 { "NetBIOSName" , "name" , isOther , &kSCPropNetSMBNetBIOSName , __doSMBName , NULL },
1465 { "name" , "name" , isOther , &kSCPropNetSMBNetBIOSName , __doSMBName , NULL },
1466 { "NetBIOSNodeType", "type" , isChooseOne, &kSCPropNetSMBNetBIOSNodeType, NULL , (void *)smbNodeTypes },
1467 { "type", "type" , isChooseOne, &kSCPropNetSMBNetBIOSNodeType, NULL , (void *)smbNodeTypes },
1468 { "Workgroup" , "workgroup", isOther , &kSCPropNetSMBWorkgroup , __doSMBWorkgroup , NULL },
1469 { "WINSAddresses" , "wins" , isOther , &kSCPropNetSMBWINSAddresses , __doSMBWINSAddresses, NULL },
1470 { "wins" , "wins" , isOther , &kSCPropNetSMBWINSAddresses , __doSMBWINSAddresses, NULL },
1471
1472 { "?" , NULL , isHelp , NULL , NULL,
1473 "\nSMB configuration commands\n\n"
1474 " set protocol name NetBIOS-name\n"
1475 " set protocol type (Broadcast|Peer|Mixed|Hybrid)\n"
1476 " set protocol workgroup SMB-workgroup\n"
1477 " set protocol wins x1.x1.x1.x1[,x2.x2.x2.x2]\n"
1478 }
1479 };
1480 #define N_SMB_OPTIONS (sizeof(smbOptions) / sizeof(smbOptions[0]))
1481
1482
1483 static Boolean
1484 set_protocol_smb(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1485 {
1486 Boolean ok;
1487
1488 ok = _process_options(smbOptions, N_SMB_OPTIONS, argc, argv, newConfiguration);
1489 return ok;
1490 }
1491
1492
1493 #endif // !TARGET_OS_IPHONE
1494
1495
1496 #pragma mark -
1497 #pragma mark *Protocol*
1498
1499
1500 __private_extern__
1501 void
1502 set_protocol(int argc, char **argv)
1503 {
1504 CFDictionaryRef configuration;
1505 CFMutableDictionaryRef newConfiguration = NULL;
1506 Boolean ok = FALSE;
1507 CFStringRef protocolType;
1508
1509 if (net_protocol == NULL) {
1510 SCPrint(TRUE, stdout, CFSTR("protocol not selected\n"));
1511 return;
1512 }
1513
1514 if (argc < 1) {
1515 SCPrint(TRUE, stdout, CFSTR("set what?\n"));
1516 return;
1517 }
1518
1519 configuration = SCNetworkProtocolGetConfiguration(net_protocol);
1520 if (configuration == NULL) {
1521 newConfiguration = CFDictionaryCreateMutable(NULL,
1522 0,
1523 &kCFTypeDictionaryKeyCallBacks,
1524 &kCFTypeDictionaryValueCallBacks);
1525 } else {
1526 newConfiguration = CFDictionaryCreateMutableCopy(NULL, 0, configuration);
1527 CFDictionaryRemoveValue(newConfiguration, kSCResvInactive);
1528 }
1529
1530 protocolType = SCNetworkProtocolGetProtocolType(net_protocol);
1531 if (CFEqual(protocolType, kSCNetworkProtocolTypeDNS)) {
1532 ok = set_protocol_dns(argc, argv, newConfiguration);
1533 } else if (CFEqual(protocolType, kSCNetworkProtocolTypeIPv4)) {
1534 ok = set_protocol_ipv4(argc, argv, newConfiguration);
1535 } else if (CFEqual(protocolType, kSCNetworkProtocolTypeIPv6)) {
1536 ok = set_protocol_ipv6(argc, argv, newConfiguration);
1537 } else if (CFEqual(protocolType, kSCNetworkProtocolTypeProxies)) {
1538 ok = set_protocol_proxies(argc, argv, newConfiguration);
1539 #if !TARGET_OS_IPHONE
1540 } else if (CFEqual(protocolType, kSCNetworkProtocolTypeSMB)) {
1541 ok = set_protocol_smb(argc, argv, newConfiguration);
1542 #endif // !TARGET_OS_IPHONE
1543 } else {
1544 SCPrint(TRUE, stdout, CFSTR("this protocols configuration cannot be changed\n"));
1545 }
1546
1547 if (!ok) {
1548 goto done;
1549 }
1550
1551 if (((configuration == NULL) && (CFDictionaryGetCount(newConfiguration) > 0)) ||
1552 ((configuration != NULL) && !CFEqual(configuration, newConfiguration))) {
1553 if (!SCNetworkProtocolSetConfiguration(net_protocol, newConfiguration)) {
1554 SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
1555 goto done;
1556 }
1557
1558 _prefs_changed = TRUE;
1559 }
1560
1561 done :
1562
1563 if (newConfiguration != NULL) CFRelease(newConfiguration);
1564 return;
1565 }
1566
1567
1568 /* -------------------- */
1569
1570
1571 __private_extern__
1572 void
1573 show_protocol(int argc, char **argv)
1574 {
1575 CFDictionaryRef configuration;
1576 SCNetworkProtocolRef protocol = NULL;
1577 CFStringRef protocolType;
1578
1579 if (argc > 0) {
1580 protocol = _find_protocol(argv[0]);
1581 } else {
1582 if (net_protocol != NULL) {
1583 protocol = net_protocol;
1584 } else {
1585 SCPrint(TRUE, stdout, CFSTR("protocol not selected\n"));
1586 return;
1587 }
1588 }
1589
1590 if (protocol == NULL) {
1591 return;
1592 }
1593
1594 protocolType = SCNetworkProtocolGetProtocolType(protocol);
1595 SCPrint(TRUE, stdout, CFSTR("protocol type = %@\n"), protocolType);
1596
1597 configuration = SCNetworkProtocolGetConfiguration(protocol);
1598 if (configuration != NULL) {
1599 SCPrint(TRUE, stdout, CFSTR("\n protocol configuration\n"));
1600 _show_entity(configuration, CFSTR(""));
1601 }
1602
1603 if (_sc_debug) {
1604 SCPrint(TRUE, stdout, CFSTR("\n%@\n"), protocol);
1605 }
1606
1607 return;
1608 }
1609
1610
1611 /* -------------------- */
1612
1613
1614 __private_extern__
1615 void
1616 show_protocols(int argc, char **argv)
1617 {
1618 #pragma unused(argc)
1619 #pragma unused(argv)
1620 CFIndex i;
1621 CFIndex n;
1622
1623 if (prefs == NULL) {
1624 SCPrint(TRUE, stdout, CFSTR("network configuration not open\n"));
1625 return;
1626 }
1627
1628 if (net_service == NULL) {
1629 SCPrint(TRUE, stdout, CFSTR("service not selected\n"));
1630 return;
1631 }
1632
1633 if (protocols != NULL) CFRelease(protocols);
1634 protocols = SCNetworkServiceCopyProtocols(net_service);
1635 if (protocols == NULL) {
1636 SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
1637 return;
1638 }
1639
1640 n = CFArrayGetCount(protocols);
1641 if (n > 1) {
1642 CFMutableArrayRef sorted;
1643
1644 sorted = CFArrayCreateMutableCopy(NULL, 0, protocols);
1645 CFArraySortValues(sorted,
1646 CFRangeMake(0, n),
1647 _SCNetworkProtocolCompare,
1648 NULL);
1649 CFRelease(protocols);
1650 protocols = sorted;
1651 }
1652
1653 for (i = 0; i < n; i++) {
1654 SCNetworkProtocolRef protocol;
1655 CFStringRef protocolType;
1656
1657 protocol = CFArrayGetValueAtIndex(protocols, i);
1658 protocolType = SCNetworkProtocolGetProtocolType(protocol);
1659
1660 SCPrint(TRUE, stdout, CFSTR("%c%2ld: %@%*s :"),
1661 ((net_protocol != NULL) && CFEqual(protocol, net_protocol)) ? '>' : ' ',
1662 i + 1,
1663 protocolType,
1664 (int)(sizeof("Proxies") - CFStringGetLength(protocolType) - 1),
1665 "");
1666
1667 if (SCNetworkProtocolGetEnabled(protocol)) {
1668 CFStringRef description;
1669
1670 description = _protocol_description(protocol, FALSE);
1671 SCPrint(TRUE, stdout, CFSTR(" %@"), description);
1672 CFRelease(description);
1673 } else {
1674 SCPrint(TRUE, stdout, CFSTR(" *DISABLED*"));
1675 }
1676 SCPrint(TRUE, stdout, CFSTR("\n"));
1677 }
1678
1679 return;
1680 }
1681
1682
1683 /* -------------------- */
1684
1685
1686 __private_extern__
1687 CF_RETURNS_RETAINED CFStringRef
1688 _protocol_description(SCNetworkProtocolRef protocol, Boolean skipEmpty)
1689 {
1690 CFDictionaryRef configuration;
1691 CFMutableStringRef description = NULL;
1692 CFStringRef protocolType;
1693
1694 description = CFStringCreateMutable(NULL, 0);
1695
1696 if (!SCNetworkProtocolGetEnabled(protocol)) {
1697 goto done;
1698 }
1699
1700 configuration = SCNetworkProtocolGetConfiguration(protocol);
1701 if (configuration == NULL) {
1702 goto done;
1703 }
1704
1705 protocolType = SCNetworkProtocolGetProtocolType(protocol);
1706 if (CFEqual(protocolType, kSCNetworkProtocolTypeDNS)) {
1707 CFStringRef domain;
1708 CFArrayRef search;
1709 CFArrayRef servers;
1710
1711 domain = CFDictionaryGetValue(configuration, kSCPropNetDNSDomainName);
1712 if (isA_CFString(domain)) {
1713 CFStringAppendFormat(description,
1714 NULL,
1715 CFSTR("domain=%@"),
1716 domain);
1717 }
1718
1719 search = CFDictionaryGetValue(configuration, kSCPropNetDNSSearchDomains);
1720 if (isA_CFArray(search)) {
1721 CFStringRef str;
1722
1723 str = CFStringCreateByCombiningStrings(NULL, search, CFSTR(","));
1724 CFStringAppendFormat(description,
1725 NULL,
1726 CFSTR("%ssearch=%@"),
1727 CFStringGetLength(description) > 0 ? ", " : "",
1728 str);
1729 CFRelease(str);
1730 }
1731
1732 servers = CFDictionaryGetValue(configuration, kSCPropNetDNSServerAddresses);
1733 if (isA_CFArray(servers)) {
1734 CFStringRef str;
1735
1736 str = CFStringCreateByCombiningStrings(NULL, servers, CFSTR(","));
1737 CFStringAppendFormat(description,
1738 NULL,
1739 CFSTR("%sservers=%@"),
1740 CFStringGetLength(description) > 0 ? ", " : "",
1741 str);
1742 CFRelease(str);
1743 }
1744 } else if (CFEqual(protocolType, kSCNetworkProtocolTypeIPv4)) {
1745 CFStringRef method;
1746
1747 method = CFDictionaryGetValue(configuration, kSCPropNetIPv4ConfigMethod);
1748 if (isA_CFString(method)) {
1749 CFArrayRef addresses;
1750
1751 addresses = CFDictionaryGetValue(configuration, kSCPropNetIPv4Addresses);
1752 if (CFEqual(method, kSCValNetIPv4ConfigMethodINFORM) &&
1753 isA_CFArray(addresses)) {
1754 CFStringAppendFormat(description,
1755 NULL,
1756 CFSTR("%@, address=%@"),
1757 method,
1758 CFArrayGetValueAtIndex(addresses, 0));
1759 } else if (CFEqual(method, kSCValNetIPv4ConfigMethodManual) &&
1760 isA_CFArray(addresses)) {
1761 CFArrayRef masks;
1762 CFStringRef router;
1763
1764 CFStringAppendFormat(description,
1765 NULL,
1766 CFSTR("%@, address=%@"),
1767 method,
1768 CFArrayGetValueAtIndex(addresses, 0));
1769
1770 if (CFDictionaryGetValueIfPresent(configuration,
1771 kSCPropNetIPv4SubnetMasks,
1772 (const void **)&masks) &&
1773 isA_CFArray(masks)) {
1774 CFStringAppendFormat(description,
1775 NULL,
1776 CFSTR(", mask=%@"),
1777 CFArrayGetValueAtIndex(masks, 0));
1778 }
1779
1780 if (CFDictionaryGetValueIfPresent(configuration,
1781 kSCPropNetIPv4Router,
1782 (const void **)&router) &&
1783 isA_CFString(router)) {
1784 CFStringAppendFormat(description,
1785 NULL,
1786 CFSTR(", router=%@"),
1787 router);
1788 }
1789 } else {
1790 CFStringAppendFormat(description,
1791 NULL,
1792 CFSTR("%@"),
1793 method);
1794 }
1795 }
1796 } else if (CFEqual(protocolType, kSCNetworkProtocolTypeIPv6)) {
1797 CFStringRef method;
1798
1799 method = CFDictionaryGetValue(configuration, kSCPropNetIPv6ConfigMethod);
1800 if (isA_CFString(method)) {
1801 CFStringAppendFormat(description,
1802 NULL,
1803 CFSTR("%@"),
1804 method);
1805 }
1806 } else if (CFEqual(protocolType, kSCNetworkProtocolTypeProxies)) {
1807 static proxyKeys *keys[] = { &proxyKeys_FTP, &proxyKeys_Gopher, &proxyKeys_HTTP, &proxyKeys_HTTPS,
1808 &proxyKeys_RTSP, &proxyKeys_SOCKS, &proxyKeys_PAC, &proxyKeys_WPAD };
1809
1810 for (size_t i = 0; i < sizeof(keys)/sizeof(keys[0]); i++) {
1811 proxyKeys *currentProxy = keys[i];
1812
1813 if (!__proxy_enabled(configuration, currentProxy->keyEnable)) {
1814 continue;
1815 }
1816
1817 if (((currentProxy->keyProxy != NULL) &&
1818 !CFDictionaryContainsKey(configuration, *(currentProxy->keyProxy))) ||
1819 ((currentProxy->keyURL != NULL) &&
1820 !CFDictionaryContainsKey(configuration, *(currentProxy->keyURL)))) {
1821 continue;
1822 }
1823
1824 CFStringAppendFormat(description,
1825 NULL,
1826 CFSTR("%s%s"),
1827 CFStringGetLength(description) > 0 ? ", " : "",
1828 currentProxy->proxy);
1829 }
1830 #if !TARGET_OS_IPHONE
1831 } else if (CFEqual(protocolType, kSCNetworkProtocolTypeSMB)) {
1832 CFStringRef name;
1833 CFArrayRef servers;
1834 CFStringRef workgroup;
1835
1836 name = CFDictionaryGetValue(configuration, kSCPropNetSMBNetBIOSName);
1837 if (isA_CFString(name)) {
1838 CFStringAppendFormat(description,
1839 NULL,
1840 CFSTR("NetBIOS name=%@"),
1841 name);
1842 }
1843
1844 workgroup = CFDictionaryGetValue(configuration, kSCPropNetSMBWorkgroup);
1845 if (isA_CFString(workgroup)) {
1846 CFStringAppendFormat(description,
1847 NULL,
1848 CFSTR("Workgroup=%@"),
1849 workgroup);
1850 }
1851
1852 servers = CFDictionaryGetValue(configuration, kSCPropNetSMBWINSAddresses);
1853 if (isA_CFArray(servers)) {
1854 CFStringRef str;
1855
1856 str = CFStringCreateByCombiningStrings(NULL, servers, CFSTR(","));
1857 CFStringAppendFormat(description,
1858 NULL,
1859 CFSTR("%sWINS servers=%@"),
1860 CFStringGetLength(description) > 0 ? ", " : "",
1861 str);
1862 CFRelease(str);
1863 }
1864 #endif // !TARGET_OS_IPHONE
1865 }
1866
1867 done :
1868
1869 if (skipEmpty && CFStringGetLength(description) == 0) {
1870 CFRelease(description);
1871 description = NULL;
1872 }
1873
1874 return description;
1875 }