]> git.saurik.com Git - apple/configd.git/blame - scutil.tproj/nc.c
configd-802.40.13.tar.gz
[apple/configd.git] / scutil.tproj / nc.c
CommitLineData
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
48CFStringRef username = NULL;
49CFStringRef password = NULL;
50CFStringRef sharedsecret = NULL;
51
52static Boolean ondemandwatch = FALSE;
53static CFStringRef ondemand_nodename = NULL;
6bb65964 54
17d3ee29 55static SCNetworkConnectionRef connection = NULL;
6bb65964
A
56static int n_callback = 0;
57
58
59/* -----------------------------------------------------------------------------
60----------------------------------------------------------------------------- */
61static void
62my_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 ----------------------------------------------------------------------------- */
74static void
75nc_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 ----------------------------------------------------------------------------- */
89static SCNetworkServiceRef
90nc_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 136done :
6bb65964
A
137
138 if (selected != NULL) CFRetain(selected);
139 if (services != NULL) CFRelease(services);
140 return selected;
141}
142
17d3ee29
A
143/* -----------------------------------------------------------------------------
144 ----------------------------------------------------------------------------- */
145static SCNetworkServiceRef
146nc_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----------------------------------------------------------------------------- */
167static char *
168nc_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
185static void
186nc_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
226static void
227nc_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
253static void
254nc_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----------------------------------------------------------------------------- */
316static void
317nc_release_connection()
318{
17d3ee29 319 my_CFRelease(&connection);
6bb65964
A
320}
321
322/* -----------------------------------------------------------------------------
323----------------------------------------------------------------------------- */
324static void
325nc_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----------------------------------------------------------------------------- */
403static void
404nc_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 ----------------------------------------------------------------------------- */
419static void
420nc_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 ----------------------------------------------------------------------------- */
432static void
433nc_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----------------------------------------------------------------------------- */
445static void
446nc_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
459static void
460nc_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----------------------------------------------------------------------------- */
494static void
495nc_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
517static void
518checkOnDemandHost(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
558static void
559nc_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
596static void
597nc_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;
665done:
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 676CFStringRef
5e9ce69e 677copy_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
695CFStringRef
696copy_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
711done:
712 my_CFRelease(&service_connection);
713 return output;
714}
17d3ee29
A
715
716static void
717nc_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----------------------------------------------------------------------------- */
765static void
766nc_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 ----------------------------------------------------------------------------- */
790static Boolean
791nc_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
830done:
831 return success;
832}
833
834/* Turns a service ID or name into a vendor type, or preserves type */
835static CFStringRef
836nc_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
863done :
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
872static const CFStringRef PREF_PREFIX = CFSTR("VPN-");
873static const CFStringRef PREF_SUFFIX = CFSTR(".plist");
874static void
875nc_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
926done:
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 ----------------------------------------------------------------------------- */
941static void
942nc_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
969done:
970 my_CFRelease(&vendorType);
971 exit(exit_code);
972}
973
6bb65964
A
974/* -----------------------------------------------------------------------------
975----------------------------------------------------------------------------- */
976static void
977nc_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);
1048skipURL:
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
1077done:
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 ----------------------------------------------------------------------------- */
1091static void
1092nc_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;
1130done:
17d3ee29 1131 my_CFRelease(&service);
6bb65964
A
1132 my_CFRelease(&current_set);
1133 _prefs_close();
1134 exit(exit_code);
1135}
1136
5e9ce69e
A
1137/* -----------------------------------------------------------------------------
1138 ----------------------------------------------------------------------------- */
1139static void
1140nc_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----------------------------------------------------------------------------- */
1199typedef void (*nc_func) (int argc, char **argv);
1200
1201static 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----------------------------------------------------------------------------- */
1224int
1225find_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----------------------------------------------------------------------------- */
1241void
1242do_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