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