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