]>
Commit | Line | Data |
---|---|---|
6bb65964 | 1 | /* |
9de8ab86 | 2 | * Copyright (c) 2010-2015 Apple Inc. All rights reserved. |
6bb65964 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
9de8ab86 | 5 | * |
6bb65964 A |
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. | |
9de8ab86 | 12 | * |
6bb65964 A |
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. | |
9de8ab86 | 20 | * |
6bb65964 A |
21 | * @APPLE_LICENSE_HEADER_END@ |
22 | */ | |
23 | ||
24 | /* | |
25 | * Modification History | |
26 | * | |
27 | * March 1, 2010 Christophe Allie <callie@apple.com> | |
28 | * - initial revision | |
29 | * February 8, 2011 Kevin Wells <kcw@apple.com> | |
30 | * - added "select" command | |
17d3ee29 A |
31 | * January 2012 Kevin Wells <kcw@apple.com> |
32 | * - added arguments to "start" command to pass authentication credentials | |
33 | * - "show" now takes a service name as an alternative to a service ID | |
34 | * - fixes a bug whereby "IPv4" was being displayed as a subtype to IPsec services | |
35 | * - improved format of "list" output | |
36 | * - general cleanup of error messages and some variable names | |
6bb65964 A |
37 | */ |
38 | ||
39 | ||
40 | #include "scutil.h" | |
41 | #include "nc.h" | |
42 | #include "prefs.h" | |
43 | ||
5e9ce69e A |
44 | #include <SystemConfiguration/VPNConfiguration.h> |
45 | ||
6bb65964 A |
46 | #include <sys/time.h> |
47 | ||
5e9ce69e A |
48 | CFStringRef username = NULL; |
49 | CFStringRef password = NULL; | |
50 | CFStringRef sharedsecret = NULL; | |
51 | ||
52 | static Boolean ondemandwatch = FALSE; | |
53 | static CFStringRef ondemand_nodename = NULL; | |
6bb65964 | 54 | |
17d3ee29 | 55 | static SCNetworkConnectionRef connection = NULL; |
6bb65964 A |
56 | static int n_callback = 0; |
57 | ||
58 | ||
59 | /* ----------------------------------------------------------------------------- | |
60 | ----------------------------------------------------------------------------- */ | |
61 | static void | |
62 | my_CFRelease(void *t) | |
63 | { | |
64 | void * * obj = (void * *)t; | |
65 | if (obj && *obj) { | |
66 | CFRelease(*obj); | |
67 | *obj = NULL; | |
68 | } | |
69 | return; | |
70 | } | |
71 | ||
72 | /* ----------------------------------------------------------------------------- | |
17d3ee29 A |
73 | ----------------------------------------------------------------------------- */ |
74 | static void | |
75 | nc_get_service_type_and_subtype(SCNetworkServiceRef service, CFStringRef *iftype, CFStringRef *ifsubtype) { | |
76 | SCNetworkInterfaceRef interface = SCNetworkServiceGetInterface(service); | |
77 | SCNetworkInterfaceRef child = SCNetworkInterfaceGetInterface(interface); | |
6bb65964 | 78 | |
17d3ee29 A |
79 | *iftype = SCNetworkInterfaceGetInterfaceType(interface); |
80 | *ifsubtype = NULL; | |
81 | if (CFEqual(*iftype, kSCNetworkInterfaceTypePPP) || | |
82 | CFEqual(*iftype, kSCNetworkInterfaceTypeVPN)) { | |
83 | *ifsubtype = (child != NULL) ? SCNetworkInterfaceGetInterfaceType(child) : NULL; | |
6bb65964 | 84 | } |
6bb65964 A |
85 | } |
86 | ||
87 | /* ----------------------------------------------------------------------------- | |
88 | ----------------------------------------------------------------------------- */ | |
89 | static SCNetworkServiceRef | |
90 | nc_copy_service(SCNetworkSetRef set, CFStringRef identifier) | |
91 | { | |
92 | CFIndex i; | |
93 | CFIndex n; | |
94 | SCNetworkServiceRef selected = NULL; | |
95 | CFArrayRef services; | |
96 | ||
97 | services = SCNetworkConnectionCopyAvailableServices(set); | |
98 | if (services == NULL) { | |
99 | goto done; | |
100 | } | |
101 | ||
102 | n = CFArrayGetCount(services); | |
103 | ||
104 | // try to select the service by its serviceID | |
105 | for (i = 0; i < n; i++) { | |
106 | SCNetworkServiceRef service = NULL; | |
107 | CFStringRef serviceID; | |
108 | ||
109 | service = CFArrayGetValueAtIndex(services, i); | |
110 | serviceID = SCNetworkServiceGetServiceID(service); | |
111 | if (CFEqual(identifier, serviceID)) { | |
112 | selected = service; | |
113 | goto done; | |
114 | } | |
115 | } | |
116 | ||
117 | // try to select the service by service name | |
118 | for (i = 0; i < n; i++) { | |
119 | SCNetworkServiceRef service = NULL; | |
120 | CFStringRef serviceName; | |
121 | ||
122 | service = CFArrayGetValueAtIndex(services, i); | |
123 | serviceName = SCNetworkServiceGetName(service); | |
124 | if ((serviceName != NULL) && CFEqual(identifier, serviceName)) { | |
125 | if (selected == NULL) { | |
126 | selected = service; | |
127 | } else { | |
128 | // if multiple services match | |
129 | selected = NULL; | |
17d3ee29 | 130 | SCPrint(TRUE, stderr, CFSTR("Multiple services match\n")); |
6bb65964 A |
131 | goto done; |
132 | } | |
133 | } | |
134 | } | |
135 | ||
17d3ee29 | 136 | done : |
6bb65964 A |
137 | |
138 | if (selected != NULL) CFRetain(selected); | |
139 | if (services != NULL) CFRelease(services); | |
140 | return selected; | |
141 | } | |
142 | ||
17d3ee29 A |
143 | /* ----------------------------------------------------------------------------- |
144 | ----------------------------------------------------------------------------- */ | |
145 | static SCNetworkServiceRef | |
146 | nc_copy_service_from_arguments(int argc, char **argv, SCNetworkSetRef set) { | |
147 | CFStringRef serviceID = NULL; | |
148 | SCNetworkServiceRef service = NULL; | |
149 | ||
150 | if (argc == 0) { | |
5e9ce69e | 151 | serviceID = _copyStringFromSTDIN(CFSTR("Service"), NULL); |
17d3ee29 A |
152 | } else { |
153 | serviceID = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); | |
154 | } | |
155 | if (serviceID == NULL) { | |
156 | SCPrint(TRUE, stderr, CFSTR("No service ID specified\n")); | |
157 | return NULL; | |
158 | } | |
159 | service = nc_copy_service(set, serviceID); | |
160 | my_CFRelease(&serviceID); | |
161 | return service; | |
162 | } | |
163 | ||
6bb65964 A |
164 | |
165 | /* ----------------------------------------------------------------------------- | |
166 | ----------------------------------------------------------------------------- */ | |
167 | static char * | |
168 | nc_status_string(SCNetworkConnectionStatus status) | |
169 | { | |
170 | switch (status) { | |
171 | case kSCNetworkConnectionInvalid: | |
172 | return "Invalid"; | |
173 | case kSCNetworkConnectionDisconnected: | |
174 | return "Disconnected"; | |
175 | case kSCNetworkConnectionConnecting: | |
176 | return "Connecting"; | |
177 | case kSCNetworkConnectionConnected: | |
178 | return "Connected"; | |
179 | case kSCNetworkConnectionDisconnecting: | |
180 | return "Disconnecting"; | |
181 | } | |
182 | return "Unknown"; | |
183 | } | |
184 | ||
185 | static void | |
186 | nc_callback(SCNetworkConnectionRef connection, SCNetworkConnectionStatus status, void *info) | |
187 | { | |
188 | int *n = (int *)info; | |
189 | CFDictionaryRef status_dict; | |
190 | ||
191 | // report status | |
192 | if (n != NULL) { | |
193 | if (*n == 0) { | |
194 | SCPrint(TRUE, stdout, CFSTR("Current status = ")); | |
195 | } else { | |
196 | struct tm tm_now; | |
197 | struct timeval tv_now; | |
198 | ||
199 | (void)gettimeofday(&tv_now, NULL); | |
200 | (void)localtime_r(&tv_now.tv_sec, &tm_now); | |
201 | ||
202 | SCPrint(TRUE, stdout, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"), | |
203 | tm_now.tm_hour, | |
204 | tm_now.tm_min, | |
205 | tm_now.tm_sec, | |
206 | tv_now.tv_usec / 1000); | |
207 | SCPrint(TRUE, stdout, CFSTR("Callback (%d) status = "), *n); | |
208 | } | |
209 | *n = *n + 1; | |
210 | } | |
211 | SCPrint(TRUE, stdout, CFSTR("%s%s%s\n"), | |
212 | nc_status_string(status), | |
213 | (status == kSCNetworkConnectionInvalid) ? ": " : "", | |
214 | (status == kSCNetworkConnectionInvalid) ? SCErrorString(SCError()) : ""); | |
215 | ||
216 | // report extended status | |
217 | status_dict = SCNetworkConnectionCopyExtendedStatus(connection); | |
218 | if (status_dict) { | |
219 | SCPrint(TRUE, stdout, CFSTR("Extended Status %@\n"), status_dict); | |
220 | CFRelease(status_dict); | |
221 | } | |
222 | ||
223 | return; | |
224 | } | |
225 | ||
226 | static void | |
227 | nc_create_connection(int argc, char **argv, Boolean exit_on_failure) | |
228 | { | |
229 | SCNetworkConnectionContext context = { 0, &n_callback, NULL, NULL, NULL }; | |
230 | SCNetworkServiceRef service; | |
6bb65964 | 231 | |
17d3ee29 | 232 | service = nc_copy_service_from_arguments(argc, argv, NULL); |
6bb65964 A |
233 | if (service == NULL) { |
234 | SCPrint(TRUE, stderr, CFSTR("No service\n")); | |
235 | if (exit_on_failure) | |
236 | exit(1); | |
237 | return; | |
238 | } | |
239 | ||
17d3ee29 A |
240 | connection = SCNetworkConnectionCreateWithService(NULL, service, nc_callback, &context); |
241 | CFRelease(service); | |
242 | if (connection == NULL) { | |
243 | SCPrint(TRUE, stderr, CFSTR("Could not create connection: %s\n"), SCErrorString(SCError())); | |
6bb65964 A |
244 | if (exit_on_failure) |
245 | exit(1); | |
246 | return; | |
247 | } | |
248 | } | |
249 | ||
5e9ce69e A |
250 | /* ----------------------------------------------------------------------------- |
251 | ----------------------------------------------------------------------------- */ | |
252 | ||
253 | static void | |
254 | nc_trigger(int argc, char **argv) | |
255 | { | |
256 | Boolean background = FALSE; | |
257 | int i; | |
258 | CFStringRef hostName = NULL; | |
259 | int port = 80; | |
260 | ||
261 | for (i = 0; i < 3 && i < argc; i++) { | |
262 | /* Parse host name. Must be first arg. */ | |
263 | if (i == 0) { | |
264 | hostName = CFStringCreateWithCString(NULL, argv[i], kCFStringEncodingUTF8); | |
265 | continue; | |
266 | } | |
267 | ||
268 | /* Check for optional background flag */ | |
269 | if (strcmp(argv[i], "background") == 0) { | |
270 | background = TRUE; | |
271 | continue; | |
272 | } | |
273 | ||
274 | /* Parse optional port number */ | |
275 | CFStringRef str = CFStringCreateWithCString(NULL, argv[i], kCFStringEncodingUTF8); | |
276 | if (str) { | |
277 | int num = CFStringGetIntValue(str); | |
278 | if (num) { | |
279 | port = num; | |
280 | } | |
281 | my_CFRelease(&str); | |
282 | } | |
283 | } | |
284 | ||
285 | if (hostName) { | |
286 | CFReadStreamRef readStream = NULL; | |
287 | CFWriteStreamRef writeStream = NULL; | |
288 | ||
289 | CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, hostName, port, &readStream, &writeStream); | |
290 | ||
291 | if (background) { | |
292 | CFReadStreamSetProperty(readStream, CFSTR("kCFStreamNetworkServiceType"), CFSTR("kCFStreamNetworkServiceTypeBackground")); | |
293 | CFWriteStreamSetProperty(writeStream, CFSTR("kCFStreamNetworkServiceType"), CFSTR("kCFStreamNetworkServiceTypeBackground")); | |
294 | } | |
295 | ||
296 | if (readStream && writeStream) { | |
297 | CFReadStreamOpen(readStream); | |
298 | CFWriteStreamOpen(writeStream); | |
299 | SCPrint(TRUE, stdout, CFSTR("Opened stream to %@, port %d%s\n"), hostName, port, background ? ", background traffic class" : ""); | |
300 | sleep(1); | |
301 | } | |
302 | ||
303 | my_CFRelease(&readStream); | |
304 | my_CFRelease(&writeStream); | |
305 | } else { | |
306 | SCPrint(TRUE, stderr, CFSTR("Invalid or missing host name\n")); | |
307 | } | |
308 | ||
309 | my_CFRelease(&hostName); | |
310 | ||
311 | exit(0); | |
312 | } | |
313 | ||
6bb65964 A |
314 | /* ----------------------------------------------------------------------------- |
315 | ----------------------------------------------------------------------------- */ | |
316 | static void | |
317 | nc_release_connection() | |
318 | { | |
17d3ee29 | 319 | my_CFRelease(&connection); |
6bb65964 A |
320 | } |
321 | ||
322 | /* ----------------------------------------------------------------------------- | |
323 | ----------------------------------------------------------------------------- */ | |
324 | static void | |
325 | nc_start(int argc, char **argv) | |
326 | { | |
17d3ee29 A |
327 | CFMutableDictionaryRef userOptions = NULL; |
328 | CFStringRef iftype = NULL; | |
329 | CFStringRef ifsubtype = NULL; | |
330 | SCNetworkServiceRef service = NULL; | |
331 | ||
6bb65964 A |
332 | nc_create_connection(argc, argv, TRUE); |
333 | ||
17d3ee29 A |
334 | service = SCNetworkConnectionGetService(connection); |
335 | nc_get_service_type_and_subtype(service, &iftype, &ifsubtype); | |
336 | ||
337 | userOptions = CFDictionaryCreateMutable(NULL, 0, | |
338 | &kCFTypeDictionaryKeyCallBacks, | |
339 | &kCFTypeDictionaryValueCallBacks); | |
6bb65964 | 340 | |
17d3ee29 A |
341 | Boolean isL2TP = (CFEqual(iftype, kSCEntNetPPP) && |
342 | (ifsubtype != NULL) && CFEqual(ifsubtype, kSCValNetInterfaceSubTypeL2TP)); | |
343 | ||
344 | if (CFEqual(iftype, kSCEntNetPPP)) { | |
345 | CFMutableDictionaryRef pppEntity = CFDictionaryCreateMutable(NULL, 0, | |
346 | &kCFTypeDictionaryKeyCallBacks, | |
347 | &kCFTypeDictionaryValueCallBacks); | |
348 | ||
349 | if (username != NULL) { | |
350 | CFDictionarySetValue(pppEntity, kSCPropNetPPPAuthName, username); | |
351 | } | |
352 | if (password != NULL) { | |
353 | CFDictionarySetValue(pppEntity, kSCPropNetPPPAuthPassword, password); | |
354 | } | |
355 | CFDictionarySetValue(userOptions, kSCEntNetPPP, pppEntity); | |
356 | my_CFRelease(&pppEntity); | |
357 | } | |
358 | if (CFEqual(iftype, kSCEntNetIPSec) || isL2TP) { | |
359 | CFMutableDictionaryRef ipsecEntity = CFDictionaryCreateMutable(NULL, 0, | |
360 | &kCFTypeDictionaryKeyCallBacks, | |
361 | &kCFTypeDictionaryValueCallBacks); | |
362 | if (!isL2TP) { | |
363 | if (username != NULL) { | |
364 | CFDictionarySetValue(ipsecEntity, kSCPropNetIPSecXAuthName, username); | |
365 | } | |
366 | if (password != NULL) { | |
367 | CFDictionarySetValue(ipsecEntity, kSCPropNetIPSecXAuthPassword, password); | |
368 | } | |
369 | } | |
370 | if (sharedsecret != NULL) { | |
371 | CFDictionarySetValue(ipsecEntity, kSCPropNetIPSecSharedSecret, sharedsecret); | |
372 | } | |
373 | CFDictionarySetValue(userOptions, kSCEntNetIPSec, ipsecEntity); | |
374 | my_CFRelease(&ipsecEntity); | |
375 | } | |
376 | if (CFEqual(iftype, kSCEntNetVPN)) { | |
377 | CFMutableDictionaryRef vpnEntity = CFDictionaryCreateMutable(NULL, 0, | |
378 | &kCFTypeDictionaryKeyCallBacks, | |
379 | &kCFTypeDictionaryValueCallBacks); | |
380 | if (username != NULL) { | |
381 | CFDictionarySetValue(vpnEntity, kSCPropNetVPNAuthName, username); | |
382 | } | |
383 | if (password != NULL) { | |
384 | CFDictionarySetValue(vpnEntity, kSCPropNetVPNAuthPassword, password); | |
385 | } | |
386 | CFDictionarySetValue(userOptions, kSCEntNetVPN, vpnEntity); | |
387 | my_CFRelease(&vpnEntity); | |
388 | } | |
389 | // If it doesn't match any VPN type, fail silently | |
390 | ||
391 | if (!SCNetworkConnectionStart(connection, userOptions, TRUE)) { | |
392 | SCPrint(TRUE, stderr, CFSTR("Could not start connection: %s\n"), SCErrorString(SCError())); | |
393 | exit(1); | |
394 | }; | |
395 | ||
396 | CFRelease(userOptions); | |
6bb65964 A |
397 | nc_release_connection(); |
398 | exit(0); | |
399 | } | |
400 | ||
401 | /* ----------------------------------------------------------------------------- | |
402 | ----------------------------------------------------------------------------- */ | |
403 | static void | |
404 | nc_stop(int argc, char **argv) | |
405 | { | |
406 | nc_create_connection(argc, argv, TRUE); | |
407 | ||
17d3ee29 A |
408 | if (!SCNetworkConnectionStop(connection, TRUE)) { |
409 | SCPrint(TRUE, stderr, CFSTR("Could not stop connection: %s\n"), SCErrorString(SCError())); | |
410 | exit(1); | |
411 | }; | |
6bb65964 A |
412 | |
413 | nc_release_connection(); | |
414 | exit(0); | |
415 | } | |
416 | ||
417 | /* ----------------------------------------------------------------------------- | |
418 | ----------------------------------------------------------------------------- */ | |
419 | static void | |
420 | nc_suspend(int argc, char **argv) | |
421 | { | |
422 | nc_create_connection(argc, argv, TRUE); | |
423 | ||
17d3ee29 | 424 | SCNetworkConnectionSuspend(connection); |
6bb65964 A |
425 | |
426 | nc_release_connection(); | |
427 | exit(0); | |
428 | } | |
429 | ||
430 | /* ----------------------------------------------------------------------------- | |
431 | ----------------------------------------------------------------------------- */ | |
432 | static void | |
433 | nc_resume(int argc, char **argv) | |
434 | { | |
435 | nc_create_connection(argc, argv, TRUE); | |
436 | ||
17d3ee29 | 437 | SCNetworkConnectionResume(connection); |
6bb65964 A |
438 | |
439 | nc_release_connection(); | |
440 | exit(0); | |
441 | } | |
442 | ||
443 | /* ----------------------------------------------------------------------------- | |
444 | ----------------------------------------------------------------------------- */ | |
445 | static void | |
446 | nc_status(int argc, char **argv) | |
447 | { | |
448 | SCNetworkConnectionStatus status; | |
449 | ||
450 | nc_create_connection(argc, argv, TRUE); | |
451 | ||
17d3ee29 A |
452 | status = SCNetworkConnectionGetStatus(connection); |
453 | nc_callback(connection, status, NULL); | |
6bb65964 A |
454 | |
455 | nc_release_connection(); | |
456 | exit(0); | |
457 | } | |
458 | ||
459 | static void | |
460 | nc_watch(int argc, char **argv) | |
461 | { | |
462 | SCNetworkConnectionStatus status; | |
463 | ||
464 | nc_create_connection(argc, argv, TRUE); | |
465 | ||
17d3ee29 | 466 | status = SCNetworkConnectionGetStatus(connection); |
6bb65964 A |
467 | |
468 | // report initial status | |
469 | n_callback = 0; | |
17d3ee29 | 470 | nc_callback(connection, status, &n_callback); |
6bb65964 A |
471 | |
472 | // setup watcher | |
473 | if (doDispatch) { | |
5e9ce69e | 474 | if (!SCNetworkConnectionSetDispatchQueue(connection, dispatch_get_main_queue())) { |
17d3ee29 | 475 | SCPrint(TRUE, stderr, CFSTR("Unable to schedule watch process: %s\n"), SCErrorString(SCError())); |
6bb65964 A |
476 | exit(1); |
477 | } | |
478 | } else { | |
17d3ee29 A |
479 | if (!SCNetworkConnectionScheduleWithRunLoop(connection, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) { |
480 | SCPrint(TRUE, stderr, CFSTR("Unable to schedule watch process: %s\n"), SCErrorString(SCError())); | |
6bb65964 A |
481 | exit(1); |
482 | } | |
483 | } | |
484 | ||
485 | // wait for changes | |
486 | CFRunLoopRun(); | |
487 | ||
488 | nc_release_connection(); | |
489 | exit(0); | |
490 | } | |
491 | ||
492 | /* ----------------------------------------------------------------------------- | |
493 | ----------------------------------------------------------------------------- */ | |
494 | static void | |
495 | nc_statistics(int argc, char **argv) | |
496 | { | |
497 | CFDictionaryRef stats_dict; | |
498 | ||
499 | nc_create_connection(argc, argv, TRUE); | |
500 | ||
17d3ee29 | 501 | stats_dict = SCNetworkConnectionCopyStatistics(connection); |
6bb65964 A |
502 | |
503 | if (stats_dict) { | |
504 | SCPrint(TRUE, stdout, CFSTR("%@\n"), stats_dict); | |
505 | } else { | |
506 | SCPrint(TRUE, stdout, CFSTR("No statistics available\n")); | |
507 | } | |
508 | ||
509 | my_CFRelease(&stats_dict); | |
510 | ||
511 | nc_release_connection(); | |
512 | exit(0); | |
513 | } | |
514 | ||
515 | /* ----------------------------------------------------------------------------- | |
516 | ----------------------------------------------------------------------------- */ | |
17d3ee29 A |
517 | static void |
518 | checkOnDemandHost(SCDynamicStoreRef store, CFStringRef nodeName, Boolean retry) | |
519 | { | |
520 | Boolean ok; | |
521 | CFStringRef connectionServiceID = NULL; | |
522 | SCNetworkConnectionStatus connectionStatus = 0; | |
523 | CFStringRef vpnRemoteAddress = NULL; | |
524 | ||
525 | SCPrint(TRUE, stdout, CFSTR("OnDemand host/domain check (%sretry)\n"), retry ? "" : "no "); | |
526 | ||
527 | ok = __SCNetworkConnectionCopyOnDemandInfoWithName(&store, | |
528 | nodeName, | |
529 | retry, | |
530 | &connectionServiceID, | |
531 | &connectionStatus, | |
532 | &vpnRemoteAddress); | |
533 | ||
534 | if (ok) { | |
535 | SCPrint(TRUE, stdout, CFSTR(" serviceID = %@\n"), connectionServiceID); | |
536 | SCPrint(TRUE, stdout, CFSTR(" remote address = %@\n"), vpnRemoteAddress); | |
537 | } else if (SCError() != kSCStatusOK) { | |
538 | SCPrint(TRUE, stdout, CFSTR("%sretry\n"), retry ? "" : "no "); | |
539 | SCPrint(TRUE, stdout, | |
540 | CFSTR(" Unable to copy OnDemand information for connection: %s\n"), | |
541 | SCErrorString(SCError())); | |
542 | } else { | |
543 | SCPrint(TRUE, stdout, CFSTR(" no match\n")); | |
544 | } | |
545 | ||
546 | if (connectionServiceID != NULL) { | |
547 | CFRelease(connectionServiceID); | |
548 | connectionServiceID = NULL; | |
549 | } | |
550 | if (vpnRemoteAddress != NULL) { | |
551 | CFRelease(vpnRemoteAddress); | |
552 | vpnRemoteAddress = NULL; | |
553 | } | |
554 | ||
555 | return; | |
556 | } | |
557 | ||
5e9ce69e A |
558 | static void |
559 | nc_ondemand_callback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info) | |
560 | { | |
561 | CFStringRef key = NULL; | |
562 | CFDictionaryRef ondemand_dict = NULL; | |
563 | struct tm tm_now; | |
564 | struct timeval tv_now; | |
565 | ||
566 | if (CFArrayGetCount(changedKeys) < 1) { | |
567 | return; | |
568 | } | |
569 | ||
570 | (void)gettimeofday(&tv_now, NULL); | |
571 | (void)localtime_r(&tv_now.tv_sec, &tm_now); | |
572 | ||
573 | SCPrint(TRUE, stdout, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"), | |
574 | tm_now.tm_hour, | |
575 | tm_now.tm_min, | |
576 | tm_now.tm_sec, | |
577 | tv_now.tv_usec / 1000); | |
578 | ||
579 | if (ondemand_nodename) { | |
580 | checkOnDemandHost(store, ondemand_nodename, FALSE); | |
581 | checkOnDemandHost(store, ondemand_nodename, TRUE); | |
582 | } else { | |
583 | key = CFArrayGetValueAtIndex(changedKeys, 0); | |
584 | ||
585 | ondemand_dict = SCDynamicStoreCopyValue(store, key); | |
586 | if (ondemand_dict) { | |
587 | SCPrint(TRUE, stdout, CFSTR("%@ %@\n"), kSCEntNetOnDemand, ondemand_dict); | |
588 | } else { | |
589 | SCPrint(TRUE, stdout, CFSTR("%@ not configured\n"), kSCEntNetOnDemand); | |
590 | } | |
591 | ||
592 | my_CFRelease(&ondemand_dict); | |
593 | } | |
594 | } | |
595 | ||
6bb65964 A |
596 | static void |
597 | nc_ondemand(int argc, char **argv) | |
598 | { | |
599 | int exit_code = 1; | |
600 | CFStringRef key = NULL; | |
601 | CFDictionaryRef ondemand_dict = NULL; | |
602 | SCDynamicStoreRef store; | |
603 | ||
5e9ce69e | 604 | store = SCDynamicStoreCreate(NULL, CFSTR("scutil --nc"), nc_ondemand_callback, NULL); |
6bb65964 | 605 | if (store == NULL) { |
17d3ee29 | 606 | SCPrint(TRUE, stderr, CFSTR("Unable to create dynamic store: %s\n"), SCErrorString(SCError())); |
6bb65964 A |
607 | goto done; |
608 | } | |
609 | ||
5e9ce69e A |
610 | if (argc == 1) { |
611 | #if !TARGET_IPHONE_SIMULATOR | |
612 | if (strcmp("--refresh", argv[0]) == 0) { | |
613 | SCNetworkConnectionRef connection = NULL; | |
614 | ||
615 | connection = SCNetworkConnectionCreate(kCFAllocatorDefault, NULL, NULL); | |
616 | if (connection && SCNetworkConnectionRefreshOnDemandState(connection)) { | |
617 | exit_code = 0; | |
618 | } | |
619 | ||
620 | if (exit_code) { | |
621 | SCPrint(TRUE, stderr, CFSTR("Unable to refresh OnDemand state: %s\n"), SCErrorString(SCError())); | |
622 | } | |
17d3ee29 | 623 | |
5e9ce69e A |
624 | my_CFRelease(&connection); |
625 | goto done; | |
626 | } | |
627 | #endif // !TARGET_IPHONE_SIMULATOR | |
628 | ||
629 | ondemand_nodename = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); | |
630 | } else if (argc != 0) { | |
631 | SCPrint(TRUE, stderr, CFSTR("Usage: scutil --nc ondemand [-W] [hostname]\n" | |
632 | " scutil --nc ondemand -- --refresh\n")); | |
6bb65964 A |
633 | goto done; |
634 | } | |
635 | ||
17d3ee29 A |
636 | key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetOnDemand); |
637 | ||
5e9ce69e A |
638 | if (ondemand_nodename) { |
639 | checkOnDemandHost(store, ondemand_nodename, FALSE); | |
640 | checkOnDemandHost(store, ondemand_nodename, TRUE); | |
6bb65964 | 641 | } else { |
5e9ce69e A |
642 | ondemand_dict = SCDynamicStoreCopyValue(store, key); |
643 | if (ondemand_dict) { | |
644 | SCPrint(TRUE, stdout, CFSTR("%@ %@\n"), kSCEntNetOnDemand, ondemand_dict); | |
645 | } else { | |
646 | SCPrint(TRUE, stdout, CFSTR("%@ not configured\n"), kSCEntNetOnDemand); | |
647 | } | |
648 | } | |
649 | ||
650 | if (ondemandwatch) { | |
651 | CFMutableArrayRef keys = NULL; | |
652 | ||
653 | keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); | |
654 | CFArrayAppendValue(keys, key); | |
655 | SCDynamicStoreSetNotificationKeys(store, keys, NULL); | |
656 | ||
657 | my_CFRelease(&keys); | |
658 | ||
659 | SCDynamicStoreSetDispatchQueue(store, dispatch_get_main_queue()); | |
660 | ||
661 | CFRunLoopRun(); | |
6bb65964 A |
662 | } |
663 | ||
664 | exit_code = 0; | |
665 | done: | |
666 | my_CFRelease(&ondemand_dict); | |
667 | my_CFRelease(&key); | |
668 | my_CFRelease(&store); | |
5e9ce69e | 669 | my_CFRelease(&ondemand_nodename); |
6bb65964 A |
670 | exit(exit_code); |
671 | } | |
672 | ||
17d3ee29 | 673 | |
6bb65964 | 674 | /* ----------------------------------------------------------------------------- |
17d3ee29 | 675 | ----------------------------------------------------------------------------- */ |
17d3ee29 | 676 | CFStringRef |
5e9ce69e | 677 | copy_padded_string(CFStringRef original, int width, CFStringRef prefix, CFStringRef suffix) |
6bb65964 | 678 | { |
17d3ee29 | 679 | CFMutableStringRef padded; |
6bb65964 | 680 | |
5e9ce69e A |
681 | padded = CFStringCreateMutable(NULL, 0); |
682 | if (prefix != NULL) { | |
683 | CFStringAppend(padded, prefix); | |
684 | } | |
685 | if (original != NULL) { | |
686 | CFStringAppend(padded, original); | |
687 | } | |
688 | if (suffix != NULL) { | |
689 | CFStringAppend(padded, suffix); | |
690 | } | |
17d3ee29 A |
691 | CFStringPad(padded, CFSTR(" "), MAX(CFStringGetLength(original), width), 0); |
692 | return padded; | |
693 | } | |
6bb65964 | 694 | |
5e9ce69e A |
695 | CFStringRef |
696 | copy_VPN_status(SCNetworkServiceRef service) | |
697 | { | |
698 | CFStringRef output = NULL; | |
699 | SCNetworkConnectionStatus status = kSCNetworkConnectionInvalid; | |
700 | SCNetworkConnectionRef service_connection = NULL; | |
701 | ||
702 | /* Only calculate status is the service is enabled. Default is invalid. */ | |
703 | if (SCNetworkServiceGetEnabled(service)) { | |
704 | service_connection = SCNetworkConnectionCreateWithService(NULL, service, NULL, NULL); | |
705 | if (service_connection == NULL) goto done; | |
706 | status = SCNetworkConnectionGetStatus(service_connection); | |
707 | } | |
708 | ||
709 | output = CFStringCreateWithCString(NULL, nc_status_string(status), kCFStringEncodingUTF8); | |
710 | ||
711 | done: | |
712 | my_CFRelease(&service_connection); | |
713 | return output; | |
714 | } | |
17d3ee29 A |
715 | |
716 | static void | |
717 | nc_print_VPN_service(SCNetworkServiceRef service) | |
718 | { | |
5e9ce69e A |
719 | SCNetworkInterfaceRef interface = NULL; |
720 | CFStringRef display_name = NULL; | |
721 | CFStringRef display_name_padded = NULL; | |
722 | CFStringRef service_id = NULL; | |
723 | CFStringRef service_name = NULL; | |
724 | CFStringRef service_name_padded = NULL; | |
725 | CFStringRef service_status = NULL; | |
726 | CFStringRef service_status_padded = NULL; | |
17d3ee29 | 727 | CFStringRef sub_type = NULL; |
5e9ce69e | 728 | CFStringRef type = NULL; |
17d3ee29 A |
729 | |
730 | nc_get_service_type_and_subtype(service, &type, &sub_type); | |
731 | ||
5e9ce69e A |
732 | service_name = SCNetworkServiceGetName(service); |
733 | service_name_padded = copy_padded_string(service_name, 32, CFSTR("\""), CFSTR("\"")); | |
17d3ee29 | 734 | |
5e9ce69e | 735 | service_id = SCNetworkServiceGetServiceID(service); |
17d3ee29 | 736 | |
5e9ce69e A |
737 | interface = SCNetworkServiceGetInterface(service); |
738 | display_name = SCNetworkInterfaceGetLocalizedDisplayName(interface); | |
739 | display_name_padded = copy_padded_string(display_name, 18, NULL, NULL); | |
740 | ||
741 | service_status = copy_VPN_status(service); | |
742 | service_status_padded = copy_padded_string(service_status, 16, CFSTR("("), CFSTR(")")); | |
17d3ee29 A |
743 | |
744 | SCPrint(TRUE, | |
745 | stdout, | |
5e9ce69e | 746 | CFSTR("%@ %@ %@ %@ %@ [%@%@%@]\n"), |
17d3ee29 | 747 | SCNetworkServiceGetEnabled(service) ? CFSTR("*") : CFSTR(" "), |
5e9ce69e | 748 | service_status_padded, |
17d3ee29 A |
749 | service_id, |
750 | display_name_padded, | |
751 | service_name_padded, | |
752 | type, | |
753 | (sub_type == NULL) ? CFSTR("") : CFSTR(":"), | |
754 | (sub_type == NULL) ? CFSTR("") : sub_type); | |
5e9ce69e | 755 | |
17d3ee29 A |
756 | CFRelease(display_name_padded); |
757 | CFRelease(service_name_padded); | |
5e9ce69e A |
758 | CFRelease(service_status_padded); |
759 | my_CFRelease(&service_status); | |
6bb65964 A |
760 | } |
761 | ||
762 | ||
763 | /* ----------------------------------------------------------------------------- | |
764 | ----------------------------------------------------------------------------- */ | |
765 | static void | |
766 | nc_list(int argc, char **argv) | |
767 | { | |
78403150 A |
768 | CFIndex count; |
769 | CFIndex i; | |
6bb65964 | 770 | CFArrayRef services = NULL; |
6bb65964 | 771 | |
17d3ee29 | 772 | SCPrint(TRUE, stdout, CFSTR("Available network connection services in the current set (*=enabled):\n")); |
6bb65964 A |
773 | services = SCNetworkConnectionCopyAvailableServices(NULL); |
774 | if (services != NULL) { | |
775 | count = CFArrayGetCount(services); | |
6bb65964 A |
776 | for (i = 0; i < count; i++) { |
777 | SCNetworkServiceRef service; | |
6bb65964 A |
778 | |
779 | service = CFArrayGetValueAtIndex(services, i); | |
17d3ee29 | 780 | nc_print_VPN_service(service); |
6bb65964 A |
781 | } |
782 | ||
6bb65964 | 783 | } |
6bb65964 | 784 | my_CFRelease(&services); |
17d3ee29 | 785 | exit(0); |
6bb65964 A |
786 | } |
787 | ||
5e9ce69e A |
788 | /* ----------------------------------------------------------------------------- |
789 | ----------------------------------------------------------------------------- */ | |
790 | static Boolean | |
791 | nc_enable_vpntype(CFStringRef vpnType) | |
792 | { | |
793 | Boolean is_enabled = FALSE; | |
794 | Boolean success = FALSE; | |
795 | ||
796 | if (vpnType == NULL) { | |
797 | SCPrint(TRUE, stderr, CFSTR("No VPN type provided\n")); | |
798 | goto done; | |
799 | } | |
800 | ||
801 | is_enabled = VPNConfigurationIsVPNTypeEnabled(vpnType); | |
802 | ||
803 | if (is_enabled) { | |
804 | SCPrint(TRUE, stdout, CFSTR("VPN is already enabled\n")); | |
805 | } else { | |
806 | #if !TARGET_OS_IPHONE | |
807 | AuthorizationRef authorization; | |
808 | ||
809 | authorization = _prefs_AuthorizationCreate(); | |
810 | if ((authorization == NULL) || | |
811 | !VPNConfigurationSetAuthorization(authorization)) { | |
812 | SCPrint(TRUE, stderr, CFSTR("VPNConfigurationSetAuthorization failed: %s\n"), SCErrorString(SCError())); | |
813 | goto done; | |
814 | } | |
815 | #endif // !TARGET_OS_IPHONE | |
816 | ||
817 | if (!VPNConfigurationEnableVPNType(vpnType)) { | |
818 | SCPrint(TRUE, stderr, CFSTR("VPN could not be enabled: %s\n"), SCErrorString(SCError())); | |
819 | goto done; | |
820 | } | |
821 | ||
822 | #if !TARGET_OS_IPHONE | |
823 | _prefs_AuthorizationFree(authorization); | |
824 | #endif // !TARGET_OS_IPHONE | |
825 | ||
826 | SCPrint(TRUE, stdout, CFSTR("VPN enabled\n")); | |
827 | } | |
828 | success = TRUE; | |
829 | ||
830 | done: | |
831 | return success; | |
832 | } | |
833 | ||
834 | /* Turns a service ID or name into a vendor type, or preserves type */ | |
835 | static CFStringRef | |
836 | nc_copy_vendor_type (CFStringRef input) | |
837 | { | |
838 | SCNetworkInterfaceRef child; | |
839 | SCNetworkInterfaceRef interface; | |
840 | CFStringRef output_name = input; | |
841 | SCNetworkServiceRef service = NULL; | |
842 | CFStringRef type; | |
843 | ||
844 | if (input == NULL) { | |
845 | goto done; | |
846 | } | |
847 | ||
848 | service = nc_copy_service(NULL, input); | |
849 | if (service != NULL) { | |
850 | interface = SCNetworkServiceGetInterface(service); | |
851 | child = SCNetworkInterfaceGetInterface(interface); | |
852 | type = SCNetworkInterfaceGetInterfaceType(interface); | |
853 | ||
854 | /* Must be of type VPN */ | |
855 | if (!CFEqual(type, kSCNetworkInterfaceTypeVPN)) { | |
856 | output_name = NULL; | |
857 | goto done; | |
858 | } | |
859 | output_name = SCNetworkInterfaceGetInterfaceType(child); | |
860 | goto done; | |
861 | } | |
862 | ||
863 | done : | |
864 | if (output_name != NULL) CFRetain(output_name); | |
865 | my_CFRelease(&service); | |
866 | return output_name; | |
867 | } | |
868 | ||
869 | /* ----------------------------------------------------------------------------- | |
870 | ----------------------------------------------------------------------------- */ | |
871 | #if !TARGET_OS_IPHONE | |
872 | static const CFStringRef PREF_PREFIX = CFSTR("VPN-"); | |
873 | static const CFStringRef PREF_SUFFIX = CFSTR(".plist"); | |
874 | static void | |
875 | nc_set_application_url(CFStringRef subtype, CFStringRef directory) | |
876 | { | |
877 | CFURLRef directory_url = NULL; | |
878 | CFDataRef directory_url_data = NULL; | |
879 | CFStringRef vpnprefpath = NULL; | |
880 | char *path = NULL; | |
881 | CFIndex path_len = 0; | |
882 | ||
883 | if (subtype == NULL || directory == NULL) { | |
884 | goto done; | |
885 | } | |
886 | ||
887 | directory_url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, | |
888 | directory, | |
889 | kCFURLPOSIXPathStyle, | |
890 | FALSE); | |
891 | if (directory_url == NULL) { | |
892 | SCPrint(TRUE, stderr, CFSTR("CFURLCreateWithFileSystemPath failed\n")); | |
893 | goto done; | |
894 | } | |
895 | ||
896 | directory_url_data = CFURLCreateBookmarkData(NULL, directory_url, 0, 0, 0, 0); | |
897 | if (directory_url_data == NULL) { | |
898 | SCPrint(TRUE, stderr, CFSTR("CFURLCreateBookmarkData failed\n")); | |
899 | goto done; | |
900 | } | |
901 | ||
902 | vpnprefpath = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@%@"), PREF_PREFIX, subtype, PREF_SUFFIX ); | |
903 | if (vpnprefpath == NULL) { | |
904 | SCPrint(TRUE, stderr, CFSTR("CFStringCreateWithFormat failed\n")); | |
905 | goto done; | |
906 | } | |
907 | ||
908 | path_len = CFStringGetLength(vpnprefpath) + 1; | |
909 | path = malloc(path_len); | |
910 | if (path == NULL) { | |
911 | goto done; | |
912 | } | |
913 | ||
914 | if (!CFStringGetCString(vpnprefpath, path, path_len, kCFStringEncodingASCII)) { | |
915 | SCPrint(TRUE, stderr, CFSTR("CFStringGetCString failed\n")); | |
916 | goto done; | |
917 | } | |
918 | ||
919 | do_prefs_init(); /* initialization */ | |
920 | do_prefs_open(1, &path); /* open prefs */ | |
921 | ||
9de8ab86 | 922 | SCPreferencesSetValue(prefs, CFSTR("ApplicationURL"), directory_url_data); |
5e9ce69e A |
923 | |
924 | _prefs_save(); | |
925 | ||
926 | done: | |
927 | my_CFRelease(&directory_url); | |
928 | my_CFRelease(&directory_url_data); | |
929 | my_CFRelease(&vpnprefpath); | |
930 | if (path) { | |
931 | free(path); | |
932 | } | |
933 | _prefs_close(); | |
934 | ||
935 | exit(0); | |
936 | } | |
937 | #endif | |
938 | ||
939 | /* ----------------------------------------------------------------------------- | |
940 | ----------------------------------------------------------------------------- */ | |
941 | static void | |
942 | nc_enablevpn(int argc, char **argv) | |
943 | { | |
944 | CFStringRef argument = NULL; | |
945 | CFStringRef vendorType = NULL; | |
946 | int exit_code = 1; | |
947 | ||
948 | if (argc == 0) { | |
949 | SCPrint(TRUE, stderr, CFSTR("No service type or ID\n")); | |
950 | } else { | |
951 | argument = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); | |
952 | vendorType = nc_copy_vendor_type(argument); | |
953 | my_CFRelease(&argument); | |
954 | ||
955 | if (!nc_enable_vpntype(vendorType)) { | |
956 | goto done; | |
957 | } | |
958 | #if !TARGET_OS_IPHONE | |
959 | if (argc >= 2) { | |
960 | argument = CFStringCreateWithCString(NULL, argv[1], kCFStringEncodingUTF8); | |
961 | nc_set_application_url(vendorType, argument); | |
962 | my_CFRelease(&argument); | |
963 | } | |
964 | #endif | |
965 | } | |
966 | ||
967 | exit_code = 0; | |
968 | ||
969 | done: | |
970 | my_CFRelease(&vendorType); | |
971 | exit(exit_code); | |
972 | } | |
973 | ||
6bb65964 A |
974 | /* ----------------------------------------------------------------------------- |
975 | ----------------------------------------------------------------------------- */ | |
976 | static void | |
977 | nc_show(int argc, char **argv) | |
978 | { | |
5e9ce69e A |
979 | SCNetworkServiceRef service = NULL; |
980 | SCDynamicStoreRef store = NULL; | |
981 | int exit_code = 1; | |
982 | CFStringRef serviceID = NULL; | |
983 | CFStringRef iftype = NULL; | |
984 | CFStringRef ifsubtype = NULL; | |
985 | CFStringRef type_entity_key = NULL; | |
986 | CFStringRef subtype_entity_key = NULL; | |
987 | CFDictionaryRef type_entity_dict = NULL; | |
988 | CFDictionaryRef subtype_entity_dict = NULL; | |
989 | CFStringRef vpnprefpath = NULL; | |
990 | #if !TARGET_OS_IPHONE | |
991 | CFDataRef bookmarkData = NULL; | |
992 | CFURLRef directory = NULL; | |
993 | Boolean isStale = FALSE; | |
994 | char *path = NULL; | |
995 | CFIndex path_len = 0; | |
996 | #endif | |
6bb65964 | 997 | |
17d3ee29 A |
998 | service = nc_copy_service_from_arguments(argc, argv, NULL); |
999 | if (service == NULL) { | |
1000 | SCPrint(TRUE, stderr, CFSTR("No service\n")); | |
1001 | exit(exit_code); | |
6bb65964 A |
1002 | } |
1003 | ||
9de8ab86 | 1004 | if (!_SCNetworkServiceIsVPN(service)) { |
17d3ee29 | 1005 | SCPrint(TRUE, stderr, CFSTR("Not a connection oriented service: %@\n"), serviceID); |
6bb65964 A |
1006 | goto done; |
1007 | } | |
1008 | ||
9de8ab86 A |
1009 | serviceID = SCNetworkServiceGetServiceID(service); |
1010 | ||
1011 | nc_get_service_type_and_subtype(service, &iftype, &ifsubtype); | |
1012 | ||
17d3ee29 A |
1013 | type_entity_key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceID, iftype); |
1014 | ||
1015 | nc_print_VPN_service(service); | |
6bb65964 | 1016 | |
5e9ce69e A |
1017 | #if !TARGET_OS_IPHONE |
1018 | vpnprefpath = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@%@"), PREF_PREFIX, ifsubtype, PREF_SUFFIX); | |
1019 | if (vpnprefpath == NULL) { | |
1020 | goto skipURL; | |
1021 | } | |
1022 | ||
1023 | path_len = CFStringGetLength(vpnprefpath) + 1; | |
1024 | path = malloc(path_len); | |
1025 | if (path == NULL) { | |
1026 | goto skipURL; | |
1027 | } | |
1028 | ||
1029 | if (!CFStringGetCString(vpnprefpath, path, path_len, kCFStringEncodingASCII)) { | |
1030 | SCPrint(TRUE, stderr, CFSTR("CFStringGetCString failed\n")); | |
1031 | goto done; | |
1032 | } | |
1033 | ||
1034 | do_prefs_init(); /* initialization */ | |
1035 | do_prefs_open(1, &path); /* open prefs */ | |
1036 | ||
1037 | bookmarkData = SCPreferencesGetValue(prefs, CFSTR("ApplicationURL")); | |
1038 | if (bookmarkData == NULL) { | |
1039 | goto skipURL; | |
1040 | } | |
1041 | ||
1042 | directory = CFURLCreateByResolvingBookmarkData(kCFAllocatorDefault, bookmarkData, 0, NULL, NULL, &isStale, NULL); | |
1043 | if (directory == NULL) { | |
1044 | goto skipURL; | |
1045 | } | |
1046 | ||
1047 | SCPrint(TRUE, stdout, CFSTR("ApplicationURL: %@\n"), directory); | |
1048 | skipURL: | |
1049 | #endif | |
1050 | ||
17d3ee29 A |
1051 | store = SCDynamicStoreCreate(NULL, CFSTR("scutil --nc"), NULL, NULL); |
1052 | if (store == NULL) { | |
1053 | SCPrint(TRUE, stderr, CFSTR("Unable to create dynamic store: %s\n"), SCErrorString(SCError())); | |
6bb65964 A |
1054 | goto done; |
1055 | } | |
1056 | type_entity_dict = SCDynamicStoreCopyValue(store, type_entity_key); | |
17d3ee29 | 1057 | |
6bb65964 | 1058 | if (!type_entity_dict) { |
17d3ee29 | 1059 | SCPrint(TRUE, stderr, CFSTR("No \"%@\" configuration available\n"), iftype); |
6bb65964 A |
1060 | } else { |
1061 | SCPrint(TRUE, stdout, CFSTR("%@ %@\n"), iftype, type_entity_dict); | |
1062 | } | |
1063 | ||
1064 | if (ifsubtype) { | |
17d3ee29 | 1065 | subtype_entity_key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceID, ifsubtype); |
6bb65964 A |
1066 | subtype_entity_dict = SCDynamicStoreCopyValue(store, subtype_entity_key); |
1067 | if (!subtype_entity_dict) { | |
1068 | // | |
1069 | } | |
1070 | else { | |
1071 | SCPrint(TRUE, stdout, CFSTR("%@ %@\n"), ifsubtype, subtype_entity_dict); | |
1072 | } | |
1073 | } | |
1074 | ||
1075 | exit_code = 0; | |
1076 | ||
1077 | done: | |
6bb65964 A |
1078 | my_CFRelease(&type_entity_key); |
1079 | my_CFRelease(&type_entity_dict); | |
1080 | my_CFRelease(&subtype_entity_key); | |
1081 | my_CFRelease(&subtype_entity_dict); | |
6bb65964 | 1082 | my_CFRelease(&store); |
17d3ee29 | 1083 | my_CFRelease(&service); |
5e9ce69e A |
1084 | my_CFRelease(&vpnprefpath); |
1085 | _prefs_close(); | |
6bb65964 A |
1086 | exit(exit_code); |
1087 | } | |
1088 | ||
1089 | /* ----------------------------------------------------------------------------- | |
1090 | ----------------------------------------------------------------------------- */ | |
1091 | static void | |
1092 | nc_select(int argc, char **argv) | |
1093 | { | |
1094 | SCNetworkSetRef current_set; | |
1095 | int exit_code = 1; | |
1096 | SCNetworkServiceRef service = NULL; | |
6bb65964 A |
1097 | Boolean status; |
1098 | ||
6bb65964 A |
1099 | do_prefs_init(); /* initialization */ |
1100 | do_prefs_open(0, NULL); /* open default prefs */ | |
1101 | ||
1102 | current_set = SCNetworkSetCopyCurrent(prefs); | |
1103 | if (current_set == NULL) { | |
78403150 | 1104 | SCPrint(TRUE, stderr, CFSTR("No current location\n")); |
6bb65964 A |
1105 | goto done; |
1106 | } | |
1107 | ||
17d3ee29 | 1108 | service = nc_copy_service_from_arguments(argc, argv, current_set); |
6bb65964 | 1109 | if (service == NULL) { |
17d3ee29 | 1110 | SCPrint(TRUE, stderr, CFSTR("No service\n")); |
6bb65964 A |
1111 | goto done; |
1112 | } | |
1113 | ||
1114 | #if !TARGET_OS_IPHONE | |
1115 | status = SCNetworkServiceSetEnabled(service, TRUE); | |
1116 | if (!status) { | |
17d3ee29 | 1117 | SCPrint(TRUE, stderr, CFSTR("Unable to enable service: %s\n"), SCErrorString(SCError())); |
6bb65964 A |
1118 | goto done; |
1119 | } | |
1120 | #else | |
1121 | status = SCNetworkSetSetSelectedVPNService(current_set, service); | |
1122 | if (!status) { | |
17d3ee29 | 1123 | SCPrint(TRUE, stderr, CFSTR("Unable to select service: %s\n"), SCErrorString(SCError())); |
6bb65964 A |
1124 | goto done; |
1125 | } | |
1126 | #endif | |
1127 | ||
1128 | _prefs_save(); | |
1129 | exit_code = 0; | |
1130 | done: | |
17d3ee29 | 1131 | my_CFRelease(&service); |
6bb65964 A |
1132 | my_CFRelease(¤t_set); |
1133 | _prefs_close(); | |
1134 | exit(exit_code); | |
1135 | } | |
1136 | ||
5e9ce69e A |
1137 | /* ----------------------------------------------------------------------------- |
1138 | ----------------------------------------------------------------------------- */ | |
1139 | static void | |
1140 | nc_help(int argc, char **argv) | |
1141 | { | |
1142 | SCPrint(TRUE, stderr, CFSTR("Valid commands for scutil --nc (VPN connections)\n")); | |
1143 | SCPrint(TRUE, stderr, CFSTR("Usage: scutil --nc [command]\n")); | |
1144 | SCPrint(TRUE, stderr, CFSTR("\n")); | |
1145 | SCPrint(TRUE, stderr, CFSTR("\tlist\n")); | |
1146 | SCPrint(TRUE, stderr, CFSTR("\t\tList available network connection services in the current set\n")); | |
1147 | SCPrint(TRUE, stderr, CFSTR("\n")); | |
1148 | SCPrint(TRUE, stderr, CFSTR("\tstatus <service>\n")); | |
1149 | SCPrint(TRUE, stderr, CFSTR("\t\tIndicate whether a given service is connected, as well as extended status information for the service\n")); | |
1150 | SCPrint(TRUE, stderr, CFSTR("\n")); | |
1151 | SCPrint(TRUE, stderr, CFSTR("\tshow <service>\n")); | |
1152 | SCPrint(TRUE, stderr, CFSTR("\t\tDisplay configuration information for a given service\n")); | |
1153 | SCPrint(TRUE, stderr, CFSTR("\n")); | |
1154 | SCPrint(TRUE, stderr, CFSTR("\tstatistics <service>\n")); | |
1155 | SCPrint(TRUE, stderr, CFSTR("\t\tProvide statistics on bytes, packets, and errors for a given service\n")); | |
1156 | SCPrint(TRUE, stderr, CFSTR("\n")); | |
1157 | SCPrint(TRUE, stderr, CFSTR("\tselect <service>\n")); | |
1158 | SCPrint(TRUE, stderr, CFSTR("\t\tMake the given service active in the current set. This allows it to be started\n")); | |
1159 | SCPrint(TRUE, stderr, CFSTR("\n")); | |
1160 | SCPrint(TRUE, stderr, CFSTR("\tstart <service> [--user user] [--password password] [--secret secret]\n")); | |
1161 | SCPrint(TRUE, stderr, CFSTR("\t\tStart a given service. Can take optional arguments for user, password, and secret\n")); | |
1162 | SCPrint(TRUE, stderr, CFSTR("\n")); | |
1163 | SCPrint(TRUE, stderr, CFSTR("\tstop <service>\n")); | |
1164 | SCPrint(TRUE, stderr, CFSTR("\t\tStop a given service\n")); | |
1165 | SCPrint(TRUE, stderr, CFSTR("\n")); | |
1166 | SCPrint(TRUE, stderr, CFSTR("\tsuspend <service>\n")); | |
1167 | SCPrint(TRUE, stderr, CFSTR("\t\tSuspend a given service (PPP, Modem on Hold)\n")); | |
1168 | SCPrint(TRUE, stderr, CFSTR("\n")); | |
1169 | SCPrint(TRUE, stderr, CFSTR("\tresume <service>\n")); | |
1170 | SCPrint(TRUE, stderr, CFSTR("\t\tResume a given service (PPP, Modem on Hold)\n")); | |
1171 | SCPrint(TRUE, stderr, CFSTR("\n")); | |
1172 | SCPrint(TRUE, stderr, CFSTR("\tondemand [-W] [hostname]\n")); | |
1173 | SCPrint(TRUE, stderr, CFSTR("\tondemand -- --refresh\n")); | |
1174 | SCPrint(TRUE, stderr, CFSTR("\t\tDisplay VPN on-demand information\n")); | |
1175 | SCPrint(TRUE, stderr, CFSTR("\n")); | |
1176 | SCPrint(TRUE, stderr, CFSTR("\ttrigger <hostname> [background] [port]\n")); | |
1177 | SCPrint(TRUE, stderr, CFSTR("\t\tTrigger VPN on-demand with specified hostname, and optional port and background flag\n")); | |
1178 | SCPrint(TRUE, stderr, CFSTR("\n")); | |
5e9ce69e A |
1179 | #if !TARGET_OS_IPHONE |
1180 | SCPrint(TRUE, stderr, CFSTR("\tenablevpn <service or vpn type> [path]\n")); | |
1181 | SCPrint(TRUE, stderr, CFSTR("\t\tEnables the given VPN application type. Takes either a service or VPN type. Pass a path to set ApplicationURL\n")); | |
1182 | SCPrint(TRUE, stderr, CFSTR("\n")); | |
1183 | #else | |
1184 | SCPrint(TRUE, stderr, CFSTR("\tenablevpn <service or vpn type>\n")); | |
1185 | SCPrint(TRUE, stderr, CFSTR("\t\tEnables the given VPN application type. Takes either a service or VPN type\n")); | |
1186 | SCPrint(TRUE, stderr, CFSTR("\n")); | |
1187 | #endif | |
1188 | SCPrint(TRUE, stderr, CFSTR("\tdisablevpn <service or vpn type>\n")); | |
1189 | SCPrint(TRUE, stderr, CFSTR("\t\tDisables the given VPN application type. Takes either a service or VPN type\n")); | |
1190 | SCPrint(TRUE, stderr, CFSTR("\n")); | |
1191 | SCPrint(TRUE, stderr, CFSTR("\thelp\n")); | |
1192 | SCPrint(TRUE, stderr, CFSTR("\t\tDisplay available commands for --nc\n")); | |
1193 | SCPrint(TRUE, stderr, CFSTR("\n")); | |
1194 | exit(0); | |
1195 | } | |
1196 | ||
6bb65964 A |
1197 | /* ----------------------------------------------------------------------------- |
1198 | ----------------------------------------------------------------------------- */ | |
1199 | typedef void (*nc_func) (int argc, char **argv); | |
1200 | ||
1201 | static const struct { | |
1202 | char *cmd; | |
1203 | nc_func func; | |
1204 | } nc_cmds[] = { | |
5e9ce69e A |
1205 | { "enablevpn", nc_enablevpn }, |
1206 | { "help", nc_help }, | |
6bb65964 A |
1207 | { "list", nc_list }, |
1208 | { "ondemand", nc_ondemand }, | |
1209 | { "resume", nc_resume }, | |
1210 | { "select", nc_select }, | |
1211 | { "show", nc_show }, | |
1212 | { "start", nc_start }, | |
1213 | { "statistics", nc_statistics }, | |
1214 | { "status", nc_status }, | |
1215 | { "stop", nc_stop }, | |
1216 | { "suspend", nc_suspend }, | |
5e9ce69e | 1217 | { "trigger", nc_trigger }, |
6bb65964 A |
1218 | }; |
1219 | #define N_NC_CMNDS (sizeof(nc_cmds) / sizeof(nc_cmds[0])) | |
1220 | ||
1221 | ||
1222 | /* ----------------------------------------------------------------------------- | |
1223 | ----------------------------------------------------------------------------- */ | |
1224 | int | |
1225 | find_nc_cmd(char *cmd) | |
1226 | { | |
1227 | int i; | |
1228 | ||
1229 | for (i = 0; i < (int)N_NC_CMNDS; i++) { | |
1230 | if (strcmp(cmd, nc_cmds[i].cmd) == 0) { | |
1231 | return i; | |
1232 | } | |
1233 | } | |
1234 | ||
1235 | return -1; | |
1236 | } | |
1237 | ||
1238 | ||
1239 | /* ----------------------------------------------------------------------------- | |
1240 | ----------------------------------------------------------------------------- */ | |
1241 | void | |
1242 | do_nc_cmd(char *cmd, int argc, char **argv, Boolean watch) | |
1243 | { | |
1244 | int i; | |
1245 | ||
1246 | i = find_nc_cmd(cmd); | |
1247 | if (i >= 0) { | |
1248 | nc_func func; | |
1249 | ||
1250 | func = nc_cmds[i].func; | |
5e9ce69e A |
1251 | if (watch) { |
1252 | if (func == nc_status) { | |
1253 | func = nc_watch; | |
1254 | } else if (func == nc_ondemand) { | |
1255 | ondemandwatch = TRUE; | |
1256 | } | |
6bb65964 A |
1257 | } |
1258 | (*func)(argc, argv); | |
1259 | } | |
1260 | return; | |
1261 | } | |
1262 |