]> git.saurik.com Git - apple/configd.git/blob - scutil.tproj/net_protocol.c
configd-1061.0.2.tar.gz
[apple/configd.git] / scutil.tproj / net_protocol.c
1 /*
2 * Copyright (c) 2004-2009, 2011, 2014, 2017, 2019 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
852 static options ipv6Options[] = {
853 { "ConfigMethod", "configuration method"
854 , isChooseOne, &kSCPropNetIPv6ConfigMethod, __doIPv6ConfigMethod, (void *)ipv6ConfigMethods },
855 { "config" , "configuration method"
856 , isChooseOne, &kSCPropNetIPv6ConfigMethod, __doIPv6ConfigMethod, (void *)ipv6ConfigMethods },
857 { "Addresses" , "address" , isOther , &kSCPropNetIPv6Addresses , __doIPv6Addresses , (void *)TRUE },
858 { "address" , "address" , isOther , &kSCPropNetIPv6Addresses , __doIPv6Addresses , (void *)TRUE },
859 { "EnableCGA" , NULL , isBoolean , &kSCPropNetIPv6EnableCGA , NULL , NULL },
860 { "PrefixLength", "prefix length", isNumber , &kSCPropNetIPv6PrefixLength, NULL , NULL },
861 { "Router" , "address" , isOther , &kSCPropNetIPv6Router , __doIPv6Addresses , (void *)FALSE },
862
863 { "?" , NULL , isHelp , NULL , NULL ,
864 "\nIPv6 configuration commands\n\n"
865 " set protocol config {Automatic|MANUAL}\n"
866 "\n w/config=Automatic\n"
867 " None\n"
868 "\n w/config=MANUAL\n"
869 " set protocol address x:x:x:x:x:x\n"
870 " set protocol router x:x:x:x:x:x\n"
871 " set protocol prefixlength n\n"
872 }
873 };
874 #define N_IPV6_OPTIONS (sizeof(ipv6Options) / sizeof(ipv6Options[0]))
875
876
877 static Boolean
878 set_protocol_ipv6(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
879 {
880 Boolean ok;
881
882 ok = _process_options(ipv6Options, N_IPV6_OPTIONS, argc, argv, newConfiguration);
883 if (ok) {
884 unsigned int flags;
885 CFStringRef method;
886 CFIndex methodIndex;
887
888 // validate configuration
889 method = CFDictionaryGetValue(newConfiguration, kSCPropNetIPv6ConfigMethod);
890 methodIndex = _find_selection(method, (selections *)ipv6ConfigMethods, &flags);
891 if (methodIndex == kCFNotFound) {
892 SCPrint(TRUE, stdout, CFSTR("unknown configuration method\n"));
893 return FALSE;
894 }
895
896 if (!(flags & allowIPv6Address) && CFDictionaryContainsKey(newConfiguration, kSCPropNetIPv6Addresses)) {
897 SCPrint(TRUE, stdout,
898 CFSTR("IP address not allowed with %@ configuration\n"),
899 ipv6ConfigMethods[methodIndex].selection);
900 return FALSE;
901 }
902
903 if (!(flags & allowIPv6PrefixLength) && CFDictionaryContainsKey(newConfiguration, kSCPropNetIPv6PrefixLength)) {
904 SCPrint(TRUE, stdout,
905 CFSTR("Prefix length not allowed with %@ configuration\n"),
906 ipv6ConfigMethods[methodIndex].selection);
907 return FALSE;
908 }
909
910 if (!(flags & allowIPv6Router) && CFDictionaryContainsKey(newConfiguration, kSCPropNetIPv6Router)) {
911 SCPrint(TRUE, stdout,
912 CFSTR("Router not allowed with %@ configuration\n"),
913 ipv6ConfigMethods[methodIndex].selection);
914 return FALSE;
915 }
916 }
917
918 return ok;
919 }
920
921
922 #pragma mark -
923 #pragma mark Proxies
924
925
926 typedef const struct {
927 const char *proxy;
928 const CFStringRef *keyEnable;
929 const CFStringRef *keyProxy;
930 const CFStringRef *keyPort;
931 const CFStringRef *keyURL;
932 } proxyKeys;
933
934 static proxyKeys proxyKeys_FTP = { "FTP" , &kSCPropNetProxiesFTPEnable , &kSCPropNetProxiesFTPProxy , &kSCPropNetProxiesFTPPort , NULL };
935 static proxyKeys proxyKeys_Gopher = { "Gopher", &kSCPropNetProxiesGopherEnable , &kSCPropNetProxiesGopherProxy, &kSCPropNetProxiesGopherPort, NULL };
936 static proxyKeys proxyKeys_HTTP = { "HTTP" , &kSCPropNetProxiesHTTPEnable , &kSCPropNetProxiesHTTPProxy , &kSCPropNetProxiesHTTPPort , NULL };
937 static proxyKeys proxyKeys_HTTPS = { "HTTPS" , &kSCPropNetProxiesHTTPSEnable , &kSCPropNetProxiesHTTPSProxy , &kSCPropNetProxiesHTTPSPort , NULL };
938 static proxyKeys proxyKeys_RTSP = { "RTSP" , &kSCPropNetProxiesRTSPEnable , &kSCPropNetProxiesRTSPProxy , &kSCPropNetProxiesRTSPPort , NULL };
939 static proxyKeys proxyKeys_SOCKS = { "SOCKS" , &kSCPropNetProxiesSOCKSEnable , &kSCPropNetProxiesSOCKSProxy , &kSCPropNetProxiesSOCKSPort , NULL };
940 static proxyKeys proxyKeys_PAC = { ".pac" , &kSCPropNetProxiesProxyAutoConfigEnable , NULL , NULL , &kSCPropNetProxiesProxyAutoConfigURLString };
941 static proxyKeys proxyKeys_WPAD = { "WPAD" , &kSCPropNetProxiesProxyAutoDiscoveryEnable, NULL , NULL , NULL };
942
943 static proxyKeys *currentProxy = NULL;
944
945
946 static int __doProxySelect (CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration);
947 static int __doProxyEnable (CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration);
948 static int __doProxyHost (CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration);
949 static int __doProxyPort (CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration);
950 static int __doProxyURL (CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration);
951 static int __doProxyFTPPassive(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration);
952
953
954 static options proxyOptions[] = {
955 // general options
956 { "ExceptionsList" , "exceptions", isStringArray, &kSCPropNetProxiesExceptionsList , NULL , NULL },
957 { "ExcludeSimpleHostnames", NULL , isBoolean , &kSCPropNetProxiesExcludeSimpleHostnames, NULL , NULL },
958 // proxy selection
959 { "FTP" , NULL , isOther , NULL , __doProxySelect , (void *)&proxyKeys_FTP },
960 { "Gopher" , NULL , isOther , NULL , __doProxySelect , (void *)&proxyKeys_Gopher },
961 { "HTTP" , NULL , isOther , NULL , __doProxySelect , (void *)&proxyKeys_HTTP },
962 { "HTTPS" , NULL , isOther , NULL , __doProxySelect , (void *)&proxyKeys_HTTPS },
963 { "RTSP" , NULL , isOther , NULL , __doProxySelect , (void *)&proxyKeys_RTSP },
964 { "SOCKS" , NULL , isOther , NULL , __doProxySelect , (void *)&proxyKeys_SOCKS },
965 { "ProxyAutoConfig" , NULL , isOther , NULL , __doProxySelect , (void *)&proxyKeys_PAC },
966 { ".pac" , NULL , isOther , NULL , __doProxySelect , (void *)&proxyKeys_PAC },
967 { "ProxyAutoDiscovery" , NULL , isOther , NULL , __doProxySelect , (void *)&proxyKeys_WPAD },
968 { "WPAD" , NULL , isOther , NULL , __doProxySelect , (void *)&proxyKeys_WPAD },
969 // proxy modifiers
970 { "disable" , NULL , isOther , NULL , __doProxyEnable , (void *)FALSE },
971 { "enable" , NULL , isOther , NULL , __doProxyEnable , (void *)TRUE },
972 { "proxy" , NULL , isOther , NULL , __doProxyHost , NULL },
973 { "host" , NULL , isOther , NULL , __doProxyHost , NULL },
974 { "port" , NULL , isOther , NULL , __doProxyPort , NULL },
975 { "url" , NULL , isOther , NULL , __doProxyURL , NULL },
976 // (ftp) proxy modifiers
977 { "FTPPassive" , NULL , isBoolean , &kSCPropNetProxiesFTPPassive , __doProxyFTPPassive, NULL },
978 { "passive" , NULL , isBoolean , &kSCPropNetProxiesFTPPassive , __doProxyFTPPassive, NULL },
979 // help
980 { "?" , NULL , isHelp , NULL , NULL ,
981 "\nProxy configuration commands\n\n"
982 " set protocol ExceptionsList exception[,exception-2]\n"
983 " set protocol ExcludeSimpleHostnames {enable|disable}\n"
984 "\n"
985 " set protocol ftp {enable|disable}\n"
986 " set protocol ftp host proxy-host\n"
987 " set protocol ftp port proxy-port\n"
988 " set protocol ftp passive {enable|disable}\n"
989 "\n"
990 " set protocol http {enable|disable}\n"
991 " set protocol http host proxy-host\n"
992 " set protocol http port proxy-port\n"
993 "\n"
994 " set protocol https {enable|disable}\n"
995 " set protocol https host proxy-host\n"
996 " set protocol https port proxy-port\n"
997 "\n"
998 " set protocol rtsp {enable|disable}\n"
999 " set protocol rtsp host proxy-host\n"
1000 " set protocol rtsp port proxy-port\n"
1001 "\n"
1002 " set protocol socks {enable|disable}\n"
1003 " set protocol socks host proxy-host\n"
1004 " set protocol socks port proxy-port\n"
1005 "\n"
1006 " set protocol .pac {enable|disable}\n"
1007 " set protocol .pac url .pac-url\n"
1008 "\n"
1009 " set protocol wpad {enable|disable}\n"
1010 }
1011 };
1012 #define N_PROXY_OPTIONS (sizeof(proxyOptions) / sizeof(proxyOptions[0]))
1013
1014
1015 static int
1016 __doProxySelect(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1017 {
1018 #pragma unused(key)
1019 #pragma unused(description)
1020 #pragma unused(newConfiguration)
1021 CFIndex nextOption;
1022
1023 if (argc < 1) {
1024 SCPrint(TRUE, stdout, CFSTR("proxy option[s] not specified\n"));
1025 return -1;
1026 }
1027
1028 currentProxy = (proxyKeys *)info;
1029
1030 nextOption = _find_option(argv[0], proxyOptions, N_PROXY_OPTIONS);
1031 if ((nextOption == kCFNotFound) ||
1032 (proxyOptions[nextOption].handler == __doProxySelect)) {
1033 SCPrint(TRUE, stdout, CFSTR("%s proxy option[s] not specified\n"), currentProxy->proxy);
1034 return -1;
1035 }
1036
1037 return 0;
1038 }
1039
1040
1041 static int
1042 __doProxyEnable(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1043 {
1044 #pragma unused(key)
1045 #pragma unused(description)
1046 #pragma unused(argc)
1047 #pragma unused(argv)
1048 Boolean enabled = (info == (void *)FALSE) ? FALSE : TRUE;
1049
1050 if (currentProxy == NULL) {
1051 SCPrint(TRUE, stdout, CFSTR("proxy not specified\n"));
1052 return -1;
1053 }
1054
1055 if (currentProxy->keyEnable == NULL) {
1056 SCPrint(TRUE, stdout, CFSTR("%s proxy cannot be %s\n"),
1057 currentProxy->proxy,
1058 enabled ? "enabled" : "disabled");
1059 return -1;
1060 }
1061
1062
1063 if (enabled) {
1064 CFDictionarySetValue(newConfiguration, *(currentProxy->keyEnable), CFNumberRef_1);
1065 } else {
1066 CFDictionaryRemoveValue(newConfiguration, *(currentProxy->keyEnable));
1067
1068 if (currentProxy->keyProxy != NULL) {
1069 CFDictionaryRemoveValue(newConfiguration, *(currentProxy->keyProxy));
1070 }
1071
1072 if (currentProxy->keyPort != NULL) {
1073 CFDictionaryRemoveValue(newConfiguration, *(currentProxy->keyPort));
1074 }
1075
1076 if (currentProxy->keyURL != NULL) {
1077 CFDictionaryRemoveValue(newConfiguration, *(currentProxy->keyURL));
1078 }
1079 }
1080
1081 return 0;
1082 }
1083
1084
1085 static Boolean
1086 __proxy_enabled(CFDictionaryRef configuration, const CFStringRef *enableKey)
1087 {
1088 CFNumberRef num;
1089 int val;
1090
1091 if (enableKey == NULL) {
1092 return TRUE; // if proxy does not need to be enabled
1093 }
1094
1095 num = CFDictionaryGetValue(configuration, *enableKey);
1096 if (!isA_CFNumber(num) ||
1097 !CFNumberGetValue(num, kCFNumberIntType, &val) ||
1098 (val == 0)) {
1099 return FALSE; // if not enabled
1100 }
1101
1102 return TRUE;
1103 }
1104
1105
1106 static int
1107 __doProxyHost(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1108 {
1109 #pragma unused(key)
1110 #pragma unused(description)
1111 #pragma unused(info)
1112 if (currentProxy == NULL) {
1113 SCPrint(TRUE, stdout, CFSTR("proxy not specified\n"));
1114 return -1;
1115 }
1116
1117 if (currentProxy->keyProxy == NULL) {
1118 SCPrint(TRUE, stdout, CFSTR("%s proxy host cannot be specified\n"), currentProxy->proxy);
1119 return -1;
1120 }
1121
1122 if (!__proxy_enabled(newConfiguration, currentProxy->keyEnable)) {
1123 SCPrint(TRUE, stdout, CFSTR("%s proxy not enabled\n"), currentProxy->proxy);
1124 return -1;
1125 }
1126
1127 if (argc < 1) {
1128 SCPrint(TRUE, stdout, CFSTR("%s proxy host not specified\n"), currentProxy->proxy);
1129 return -1;
1130 }
1131
1132 if (strlen(argv[0]) > 0) {
1133 CFStringRef host;
1134
1135 host = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
1136 CFDictionarySetValue(newConfiguration, *(currentProxy->keyProxy), host);
1137 CFRelease(host);
1138 } else {
1139 CFDictionaryRemoveValue(newConfiguration, *(currentProxy->keyProxy));
1140 }
1141
1142 return 1;
1143 }
1144
1145
1146 static int
1147 __doProxyPort(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1148 {
1149 #pragma unused(key)
1150 #pragma unused(description)
1151 #pragma unused(info)
1152 if (currentProxy == NULL) {
1153 SCPrint(TRUE, stdout, CFSTR("proxy not specified\n"));
1154 return -1;
1155 }
1156
1157 if (currentProxy->keyPort == NULL) {
1158 SCPrint(TRUE, stdout, CFSTR("%s proxy port cannot be specified\n"), currentProxy->proxy);
1159 return -1;
1160 }
1161
1162 if (!__proxy_enabled(newConfiguration, currentProxy->keyEnable)) {
1163 SCPrint(TRUE, stdout, CFSTR("%s proxy not enabled\n"), currentProxy->proxy);
1164 return -1;
1165 }
1166
1167 if (argc < 1) {
1168 SCPrint(TRUE, stdout, CFSTR("%s proxy port not specified\n"), currentProxy->proxy);
1169 return -1;
1170 }
1171
1172 if (strlen(argv[0]) > 0) {
1173 CFNumberRef num;
1174 int port;
1175
1176 num = _copy_number(argv[0]);
1177 if (!isA_CFNumber(num) ||
1178 !CFNumberGetValue(num, kCFNumberIntType, &port) ||
1179 (port < 0) || (port > 65535)) {
1180 SCPrint(TRUE, stdout, CFSTR("invalid %s proxy port number\n"), currentProxy->proxy);
1181 if (num != NULL) CFRelease(num);
1182 return -1;
1183 }
1184
1185 CFDictionarySetValue(newConfiguration, *(currentProxy->keyPort), num);
1186 CFRelease(num);
1187 } else {
1188 CFDictionaryRemoveValue(newConfiguration, *(currentProxy->keyPort));
1189 }
1190
1191 return 1;
1192 }
1193
1194
1195 static int
1196 __doProxyURL(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1197 {
1198 #pragma unused(key)
1199 #pragma unused(description)
1200 #pragma unused(info)
1201 if (currentProxy == NULL) {
1202 SCPrint(TRUE, stdout, CFSTR("proxy not specified\n"));
1203 return -1;
1204 }
1205
1206 if (currentProxy->keyURL == NULL) {
1207 SCPrint(TRUE, stdout, CFSTR("%s proxy URL cannot be specified\n"), currentProxy->proxy);
1208 return -1;
1209 }
1210
1211 if (!__proxy_enabled(newConfiguration, currentProxy->keyEnable)) {
1212 SCPrint(TRUE, stdout, CFSTR("%s proxy not enabled\n"), currentProxy->proxy);
1213 return -1;
1214 }
1215
1216 if (argc < 1) {
1217 SCPrint(TRUE, stdout, CFSTR("%s proxy URL not specified\n"), currentProxy->proxy);
1218 return -1;
1219 }
1220
1221 if (strlen(argv[0]) > 0) {
1222 CFStringRef url;
1223
1224 url = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
1225 CFDictionarySetValue(newConfiguration, *(currentProxy->keyURL), url);
1226 CFRelease(url);
1227 } else {
1228 CFDictionaryRemoveValue(newConfiguration, *(currentProxy->keyURL));
1229 }
1230
1231 return 1;
1232 }
1233
1234
1235 static int
1236 __doProxyFTPPassive(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1237 {
1238 #pragma unused(key)
1239 #pragma unused(description)
1240 #pragma unused(info)
1241 #pragma unused(argc)
1242 #pragma unused(argv)
1243 #pragma unused(newConfiguration)
1244 if (currentProxy == NULL) {
1245 SCPrint(TRUE, stdout, CFSTR("proxy not specified\n"));
1246 return -1;
1247 }
1248
1249 if (currentProxy != &proxyKeys_FTP) {
1250 SCPrint(TRUE, stdout, CFSTR("passive can only be enable for FTP proxy\n"));
1251 return -1;
1252 }
1253
1254 return 0;
1255 }
1256
1257
1258 static Boolean
1259 set_protocol_proxies(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1260 {
1261 Boolean ok;
1262
1263 ok = _process_options(proxyOptions, N_PROXY_OPTIONS, argc, argv, newConfiguration);
1264 return ok;
1265 }
1266
1267
1268 #pragma mark -
1269 #pragma mark SMB
1270
1271
1272 #if !TARGET_OS_IPHONE
1273
1274
1275 static CF_RETURNS_RETAINED CFStringRef
1276 __cleanupName(CFStringRef name)
1277 {
1278 CFMutableStringRef newName;
1279
1280 newName = CFStringCreateMutableCopy(NULL, 0, name);
1281 CFStringTrimWhitespace(newName);
1282 if (CFStringGetLength(newName) == 0) {
1283 CFRelease(newName);
1284 newName = NULL;
1285 }
1286
1287 return newName;
1288 }
1289
1290
1291 static int
1292 __doSMBName(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1293 {
1294 #pragma unused(description)
1295 #pragma unused(info)
1296 if (argc < 1) {
1297 SCPrint(TRUE, stdout, CFSTR("NetBIOS name not specified\n"));
1298 return -1;
1299 }
1300
1301 if (strlen(argv[0]) > 0) {
1302 CFStringRef name;
1303 CFStringRef str;
1304
1305 str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
1306 name = __cleanupName(str);
1307 CFRelease(str);
1308
1309 if (name != NULL) {
1310 CFDictionarySetValue(newConfiguration, key, name);
1311 CFRelease(name);
1312 } else {
1313 SCPrint(TRUE, stdout, CFSTR("invalid NetBIOS name\n"));
1314 return -1;
1315 }
1316 } else {
1317 CFDictionaryRemoveValue(newConfiguration, key);
1318 }
1319
1320 return 1;
1321 }
1322
1323
1324 static int
1325 __doSMBWorkgroup(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("Workgroup 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 Workgroup\n"));
1347 return -1;
1348 }
1349 } else {
1350 CFDictionaryRemoveValue(newConfiguration, key);
1351 }
1352
1353 return 1;
1354 }
1355
1356
1357 static int
1358 __doSMBWINSAddresses(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1359 {
1360 #pragma unused(description)
1361 #pragma unused(info)
1362 CFMutableArrayRef servers;
1363
1364 if (argc < 1) {
1365 SCPrint(TRUE, stdout, CFSTR("WINS address(es) not specified\n"));
1366 return -1;
1367 }
1368
1369 servers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1370
1371 if (strlen(argv[0]) > 0) {
1372 CFArrayRef array;
1373 CFIndex i;
1374 CFIndex n;
1375 CFStringRef str;
1376
1377 str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
1378 array = CFStringCreateArrayBySeparatingStrings(NULL, str, CFSTR(","));
1379 CFRelease(str);
1380
1381 n = (array != NULL) ? CFArrayGetCount(array) : 0;
1382 for (i = 0; i < n; i++) {
1383 char str[32];
1384
1385 if (_SC_cfstring_to_cstring(CFArrayGetValueAtIndex(array, i),
1386 str,
1387 sizeof(str),
1388 kCFStringEncodingUTF8) != NULL) {
1389 CFStringRef server;
1390
1391 server = __copyIPv4Address(str);
1392 //if (server == NULL) {
1393 // server = __copyIPv6Address(str);
1394 //}
1395 if (server != NULL) {
1396 CFArrayAppendValue(servers, server);
1397 CFRelease(server);
1398 continue;
1399 }
1400 }
1401
1402 SCPrint(TRUE, stdout, CFSTR("invalid WINS address\n"));
1403 CFRelease(array);
1404 CFRelease(servers);
1405 return -1;
1406 }
1407 if (array != NULL) CFRelease(array);
1408 }
1409
1410 if (CFArrayGetCount(servers) > 0) {
1411 CFDictionarySetValue(newConfiguration, key, servers);
1412 } else {
1413 CFDictionaryRemoveValue(newConfiguration, key);
1414 }
1415
1416 CFRelease(servers);
1417 return 1;
1418 }
1419
1420
1421 static selections smbNodeTypes[] = {
1422 { CFSTR("Broadcast"), &kSCValNetSMBNetBIOSNodeTypeBroadcast, 0 },
1423 { CFSTR("Peer") , &kSCValNetSMBNetBIOSNodeTypePeer , 0 },
1424 { CFSTR("Mixed") , &kSCValNetSMBNetBIOSNodeTypeMixed , 0 },
1425 { CFSTR("Hybrid") , &kSCValNetSMBNetBIOSNodeTypeHybrid , 0 },
1426 { NULL , NULL , 0 }
1427 };
1428
1429
1430 static options smbOptions[] = {
1431 { "NetBIOSName" , "name" , isOther , &kSCPropNetSMBNetBIOSName , __doSMBName , NULL },
1432 { "name" , "name" , isOther , &kSCPropNetSMBNetBIOSName , __doSMBName , NULL },
1433 { "NetBIOSNodeType", "type" , isChooseOne, &kSCPropNetSMBNetBIOSNodeType, NULL , (void *)smbNodeTypes },
1434 { "type", "type" , isChooseOne, &kSCPropNetSMBNetBIOSNodeType, NULL , (void *)smbNodeTypes },
1435 { "Workgroup" , "workgroup", isOther , &kSCPropNetSMBWorkgroup , __doSMBWorkgroup , NULL },
1436 { "WINSAddresses" , "wins" , isOther , &kSCPropNetSMBWINSAddresses , __doSMBWINSAddresses, NULL },
1437 { "wins" , "wins" , isOther , &kSCPropNetSMBWINSAddresses , __doSMBWINSAddresses, NULL },
1438
1439 { "?" , NULL , isHelp , NULL , NULL,
1440 "\nSMB configuration commands\n\n"
1441 " set protocol name NetBIOS-name\n"
1442 " set protocol type (Broadcast|Peer|Mixed|Hybrid)\n"
1443 " set protocol workgroup SMB-workgroup\n"
1444 " set protocol wins x1.x1.x1.x1[,x2.x2.x2.x2]\n"
1445 }
1446 };
1447 #define N_SMB_OPTIONS (sizeof(smbOptions) / sizeof(smbOptions[0]))
1448
1449
1450 static Boolean
1451 set_protocol_smb(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
1452 {
1453 Boolean ok;
1454
1455 ok = _process_options(smbOptions, N_SMB_OPTIONS, argc, argv, newConfiguration);
1456 return ok;
1457 }
1458
1459
1460 #endif // !TARGET_OS_IPHONE
1461
1462
1463 #pragma mark -
1464 #pragma mark *Protocol*
1465
1466
1467 __private_extern__
1468 void
1469 set_protocol(int argc, char **argv)
1470 {
1471 CFDictionaryRef configuration;
1472 CFMutableDictionaryRef newConfiguration = NULL;
1473 Boolean ok = FALSE;
1474 CFStringRef protocolType;
1475
1476 if (net_protocol == NULL) {
1477 SCPrint(TRUE, stdout, CFSTR("protocol not selected\n"));
1478 return;
1479 }
1480
1481 if (argc < 1) {
1482 SCPrint(TRUE, stdout, CFSTR("set what?\n"));
1483 return;
1484 }
1485
1486 configuration = SCNetworkProtocolGetConfiguration(net_protocol);
1487 if (configuration == NULL) {
1488 newConfiguration = CFDictionaryCreateMutable(NULL,
1489 0,
1490 &kCFTypeDictionaryKeyCallBacks,
1491 &kCFTypeDictionaryValueCallBacks);
1492 } else {
1493 newConfiguration = CFDictionaryCreateMutableCopy(NULL, 0, configuration);
1494 CFDictionaryRemoveValue(newConfiguration, kSCResvInactive);
1495 }
1496
1497 protocolType = SCNetworkProtocolGetProtocolType(net_protocol);
1498 if (CFEqual(protocolType, kSCNetworkProtocolTypeDNS)) {
1499 ok = set_protocol_dns(argc, argv, newConfiguration);
1500 } else if (CFEqual(protocolType, kSCNetworkProtocolTypeIPv4)) {
1501 ok = set_protocol_ipv4(argc, argv, newConfiguration);
1502 } else if (CFEqual(protocolType, kSCNetworkProtocolTypeIPv6)) {
1503 ok = set_protocol_ipv6(argc, argv, newConfiguration);
1504 } else if (CFEqual(protocolType, kSCNetworkProtocolTypeProxies)) {
1505 ok = set_protocol_proxies(argc, argv, newConfiguration);
1506 #if !TARGET_OS_IPHONE
1507 } else if (CFEqual(protocolType, kSCNetworkProtocolTypeSMB)) {
1508 ok = set_protocol_smb(argc, argv, newConfiguration);
1509 #endif // !TARGET_OS_IPHONE
1510 } else {
1511 SCPrint(TRUE, stdout, CFSTR("this protocols configuration cannot be changed\n"));
1512 }
1513
1514 if (!ok) {
1515 goto done;
1516 }
1517
1518 if (((configuration == NULL) && (CFDictionaryGetCount(newConfiguration) > 0)) ||
1519 ((configuration != NULL) && !CFEqual(configuration, newConfiguration))) {
1520 if (!SCNetworkProtocolSetConfiguration(net_protocol, newConfiguration)) {
1521 SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
1522 goto done;
1523 }
1524
1525 _prefs_changed = TRUE;
1526 }
1527
1528 done :
1529
1530 if (newConfiguration != NULL) CFRelease(newConfiguration);
1531 return;
1532 }
1533
1534
1535 /* -------------------- */
1536
1537
1538 __private_extern__
1539 void
1540 show_protocol(int argc, char **argv)
1541 {
1542 CFDictionaryRef configuration;
1543 SCNetworkProtocolRef protocol = NULL;
1544 CFStringRef protocolType;
1545
1546 if (argc > 0) {
1547 protocol = _find_protocol(argv[0]);
1548 } else {
1549 if (net_protocol != NULL) {
1550 protocol = net_protocol;
1551 } else {
1552 SCPrint(TRUE, stdout, CFSTR("protocol not selected\n"));
1553 return;
1554 }
1555 }
1556
1557 if (protocol == NULL) {
1558 return;
1559 }
1560
1561 protocolType = SCNetworkProtocolGetProtocolType(protocol);
1562 SCPrint(TRUE, stdout, CFSTR("protocol type = %@\n"), protocolType);
1563
1564 configuration = SCNetworkProtocolGetConfiguration(protocol);
1565 if (configuration != NULL) {
1566 SCPrint(TRUE, stdout, CFSTR("\n protocol configuration\n"));
1567 _show_entity(configuration, CFSTR(""));
1568 }
1569
1570 if (_sc_debug) {
1571 SCPrint(TRUE, stdout, CFSTR("\n%@\n"), protocol);
1572 }
1573
1574 return;
1575 }
1576
1577
1578 /* -------------------- */
1579
1580
1581 __private_extern__
1582 void
1583 show_protocols(int argc, char **argv)
1584 {
1585 #pragma unused(argc)
1586 #pragma unused(argv)
1587 CFIndex i;
1588 CFIndex n;
1589
1590 if (prefs == NULL) {
1591 SCPrint(TRUE, stdout, CFSTR("network configuration not open\n"));
1592 return;
1593 }
1594
1595 if (net_service == NULL) {
1596 SCPrint(TRUE, stdout, CFSTR("service not selected\n"));
1597 return;
1598 }
1599
1600 if (protocols != NULL) CFRelease(protocols);
1601 protocols = SCNetworkServiceCopyProtocols(net_service);
1602 if (protocols == NULL) {
1603 SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
1604 return;
1605 }
1606
1607 n = CFArrayGetCount(protocols);
1608 if (n > 1) {
1609 CFMutableArrayRef sorted;
1610
1611 sorted = CFArrayCreateMutableCopy(NULL, 0, protocols);
1612 CFArraySortValues(sorted,
1613 CFRangeMake(0, n),
1614 _SCNetworkProtocolCompare,
1615 NULL);
1616 CFRelease(protocols);
1617 protocols = sorted;
1618 }
1619
1620 for (i = 0; i < n; i++) {
1621 SCNetworkProtocolRef protocol;
1622 CFStringRef protocolType;
1623
1624 protocol = CFArrayGetValueAtIndex(protocols, i);
1625 protocolType = SCNetworkProtocolGetProtocolType(protocol);
1626
1627 SCPrint(TRUE, stdout, CFSTR("%c%2ld: %@%*s :"),
1628 ((net_protocol != NULL) && CFEqual(protocol, net_protocol)) ? '>' : ' ',
1629 i + 1,
1630 protocolType,
1631 (int)(sizeof("Proxies") - CFStringGetLength(protocolType) - 1),
1632 "");
1633
1634 if (SCNetworkProtocolGetEnabled(protocol)) {
1635 CFStringRef description;
1636
1637 description = _protocol_description(protocol, FALSE);
1638 SCPrint(TRUE, stdout, CFSTR(" %@"), description);
1639 CFRelease(description);
1640 } else {
1641 SCPrint(TRUE, stdout, CFSTR(" *DISABLED*"));
1642 }
1643 SCPrint(TRUE, stdout, CFSTR("\n"));
1644 }
1645
1646 return;
1647 }
1648
1649
1650 /* -------------------- */
1651
1652
1653 __private_extern__
1654 CF_RETURNS_RETAINED CFStringRef
1655 _protocol_description(SCNetworkProtocolRef protocol, Boolean skipEmpty)
1656 {
1657 CFDictionaryRef configuration;
1658 CFMutableStringRef description = NULL;
1659 CFStringRef protocolType;
1660
1661 description = CFStringCreateMutable(NULL, 0);
1662
1663 if (!SCNetworkProtocolGetEnabled(protocol)) {
1664 goto done;
1665 }
1666
1667 configuration = SCNetworkProtocolGetConfiguration(protocol);
1668 if (configuration == NULL) {
1669 goto done;
1670 }
1671
1672 protocolType = SCNetworkProtocolGetProtocolType(protocol);
1673 if (CFEqual(protocolType, kSCNetworkProtocolTypeDNS)) {
1674 CFStringRef domain;
1675 CFArrayRef search;
1676 CFArrayRef servers;
1677
1678 domain = CFDictionaryGetValue(configuration, kSCPropNetDNSDomainName);
1679 if (isA_CFString(domain)) {
1680 CFStringAppendFormat(description,
1681 NULL,
1682 CFSTR("domain=%@"),
1683 domain);
1684 }
1685
1686 search = CFDictionaryGetValue(configuration, kSCPropNetDNSSearchDomains);
1687 if (isA_CFArray(search)) {
1688 CFStringRef str;
1689
1690 str = CFStringCreateByCombiningStrings(NULL, search, CFSTR(","));
1691 CFStringAppendFormat(description,
1692 NULL,
1693 CFSTR("%ssearch=%@"),
1694 CFStringGetLength(description) > 0 ? ", " : "",
1695 str);
1696 CFRelease(str);
1697 }
1698
1699 servers = CFDictionaryGetValue(configuration, kSCPropNetDNSServerAddresses);
1700 if (isA_CFArray(servers)) {
1701 CFStringRef str;
1702
1703 str = CFStringCreateByCombiningStrings(NULL, servers, CFSTR(","));
1704 CFStringAppendFormat(description,
1705 NULL,
1706 CFSTR("%sservers=%@"),
1707 CFStringGetLength(description) > 0 ? ", " : "",
1708 str);
1709 CFRelease(str);
1710 }
1711 } else if (CFEqual(protocolType, kSCNetworkProtocolTypeIPv4)) {
1712 CFStringRef method;
1713
1714 method = CFDictionaryGetValue(configuration, kSCPropNetIPv4ConfigMethod);
1715 if (isA_CFString(method)) {
1716 CFArrayRef addresses;
1717
1718 addresses = CFDictionaryGetValue(configuration, kSCPropNetIPv4Addresses);
1719 if (CFEqual(method, kSCValNetIPv4ConfigMethodINFORM) &&
1720 isA_CFArray(addresses)) {
1721 CFStringAppendFormat(description,
1722 NULL,
1723 CFSTR("%@, address=%@"),
1724 method,
1725 CFArrayGetValueAtIndex(addresses, 0));
1726 } else if (CFEqual(method, kSCValNetIPv4ConfigMethodManual) &&
1727 isA_CFArray(addresses)) {
1728 CFArrayRef masks;
1729 CFStringRef router;
1730
1731 CFStringAppendFormat(description,
1732 NULL,
1733 CFSTR("%@, address=%@"),
1734 method,
1735 CFArrayGetValueAtIndex(addresses, 0));
1736
1737 if (CFDictionaryGetValueIfPresent(configuration,
1738 kSCPropNetIPv4SubnetMasks,
1739 (const void **)&masks) &&
1740 isA_CFArray(masks)) {
1741 CFStringAppendFormat(description,
1742 NULL,
1743 CFSTR(", mask=%@"),
1744 CFArrayGetValueAtIndex(masks, 0));
1745 }
1746
1747 if (CFDictionaryGetValueIfPresent(configuration,
1748 kSCPropNetIPv4Router,
1749 (const void **)&router) &&
1750 isA_CFString(router)) {
1751 CFStringAppendFormat(description,
1752 NULL,
1753 CFSTR(", router=%@"),
1754 router);
1755 }
1756 } else {
1757 CFStringAppendFormat(description,
1758 NULL,
1759 CFSTR("%@"),
1760 method);
1761 }
1762 }
1763 } else if (CFEqual(protocolType, kSCNetworkProtocolTypeIPv6)) {
1764 CFStringRef method;
1765
1766 method = CFDictionaryGetValue(configuration, kSCPropNetIPv6ConfigMethod);
1767 if (isA_CFString(method)) {
1768 CFStringAppendFormat(description,
1769 NULL,
1770 CFSTR("%@"),
1771 method);
1772 }
1773 } else if (CFEqual(protocolType, kSCNetworkProtocolTypeProxies)) {
1774 static proxyKeys *keys[] = { &proxyKeys_FTP, &proxyKeys_Gopher, &proxyKeys_HTTP, &proxyKeys_HTTPS,
1775 &proxyKeys_RTSP, &proxyKeys_SOCKS, &proxyKeys_PAC, &proxyKeys_WPAD };
1776
1777 for (size_t i = 0; i < sizeof(keys)/sizeof(keys[0]); i++) {
1778 proxyKeys *currentProxy = keys[i];
1779
1780 if (!__proxy_enabled(configuration, currentProxy->keyEnable)) {
1781 continue;
1782 }
1783
1784 if (((currentProxy->keyProxy != NULL) &&
1785 !CFDictionaryContainsKey(configuration, *(currentProxy->keyProxy))) ||
1786 ((currentProxy->keyURL != NULL) &&
1787 !CFDictionaryContainsKey(configuration, *(currentProxy->keyURL)))) {
1788 continue;
1789 }
1790
1791 CFStringAppendFormat(description,
1792 NULL,
1793 CFSTR("%s%s"),
1794 CFStringGetLength(description) > 0 ? ", " : "",
1795 currentProxy->proxy);
1796 }
1797 #if !TARGET_OS_IPHONE
1798 } else if (CFEqual(protocolType, kSCNetworkProtocolTypeSMB)) {
1799 CFStringRef name;
1800 CFArrayRef servers;
1801 CFStringRef workgroup;
1802
1803 name = CFDictionaryGetValue(configuration, kSCPropNetSMBNetBIOSName);
1804 if (isA_CFString(name)) {
1805 CFStringAppendFormat(description,
1806 NULL,
1807 CFSTR("NetBIOS name=%@"),
1808 name);
1809 }
1810
1811 workgroup = CFDictionaryGetValue(configuration, kSCPropNetSMBWorkgroup);
1812 if (isA_CFString(workgroup)) {
1813 CFStringAppendFormat(description,
1814 NULL,
1815 CFSTR("Workgroup=%@"),
1816 workgroup);
1817 }
1818
1819 servers = CFDictionaryGetValue(configuration, kSCPropNetSMBWINSAddresses);
1820 if (isA_CFArray(servers)) {
1821 CFStringRef str;
1822
1823 str = CFStringCreateByCombiningStrings(NULL, servers, CFSTR(","));
1824 CFStringAppendFormat(description,
1825 NULL,
1826 CFSTR("%sWINS servers=%@"),
1827 CFStringGetLength(description) > 0 ? ", " : "",
1828 str);
1829 CFRelease(str);
1830 }
1831 #endif // !TARGET_OS_IPHONE
1832 }
1833
1834 done :
1835
1836 if (skipEmpty && CFStringGetLength(description) == 0) {
1837 CFRelease(description);
1838 description = NULL;
1839 }
1840
1841 return description;
1842 }