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