/*
- * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
- *
+ *
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
- *
+ *
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
- *
+ *
* @APPLE_LICENSE_HEADER_END@
*/
* - initial revision
*/
+#include <TargetConditionals.h>
#include <ctype.h>
#include <getopt.h>
#include <stdio.h>
#include "commands.h"
#include "dictionary.h"
#include "net.h"
+#include "nc.h"
#include "prefs.h"
#include "session.h"
#include "tests.h"
-#include "SCDynamicStoreInternal.h"
-
-
-#define LINE_LENGTH 256
-
+#define LINE_LENGTH 2048
__private_extern__ AuthorizationRef authorization = NULL;
__private_extern__ InputRef currentInput = NULL;
+__private_extern__ Boolean doDispatch = FALSE;
__private_extern__ int nesting = 0;
+__private_extern__ SCPreferencesRef ni_prefs = NULL;
__private_extern__ CFRunLoopRef notifyRl = NULL;
__private_extern__ CFRunLoopSourceRef notifyRls = NULL;
__private_extern__ SCPreferencesRef prefs = NULL;
+__private_extern__ char *prefsPath = NULL;
__private_extern__ SCDynamicStoreRef store = NULL;
__private_extern__ CFPropertyListRef value = NULL;
__private_extern__ CFMutableArrayRef watchedKeys = NULL;
static const struct option longopts[] = {
// { "debug", no_argument, NULL, 'd' },
+// { "dispatch", no_argument, NULL, 'D' },
// { "verbose", no_argument, NULL, 'v' },
// { "SPI", no_argument, NULL, 'p' },
// { "check-reachability", required_argument, NULL, 'r' },
// { "timeout", required_argument, NULL, 't' },
// { "wait-key", required_argument, NULL, 'w' },
+// { "watch-reachability", no_argument, NULL, 'W' },
+ { "configuration", no_argument, NULL, 0 },
{ "dns", no_argument, NULL, 0 },
{ "get", required_argument, NULL, 0 },
+ { "error", required_argument, NULL, 0 },
{ "help", no_argument, NULL, '?' },
+ { "nc", required_argument, NULL, 0 },
{ "net", no_argument, NULL, 0 },
+ { "nwi", no_argument, NULL, 0 },
{ "prefs", no_argument, NULL, 0 },
{ "proxy", no_argument, NULL, 0 },
+ { "renew", required_argument, NULL, 0 },
{ "set", required_argument, NULL, 0 },
+ { "snapshot", no_argument, NULL, 0 },
+ { "user", required_argument, NULL, 0 },
+ { "password", required_argument, NULL, 0 },
+ { "secret", required_argument, NULL, 0 },
+ { "log", required_argument, NULL, 0 },
+ { "advisory", required_argument, NULL, 0 },
+#if !TARGET_OS_IPHONE
+ { "allow-new-interfaces", no_argument, NULL, 0 },
+#endif // !TARGET_OS_IPHONE
+ { "disable-until-needed", no_argument, NULL, 0 },
{ NULL, 0, NULL, 0 }
};
+__private_extern__
+CFStringRef
+_copyStringFromSTDIN(CFStringRef prompt, CFStringRef defaultValue)
+{
+ char buf[1024];
+ int i;
+ Boolean is_user_prompt = (prompt != NULL && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO));
+ int len;
+ char *modbuf;
+ int modlen;
+ CFStringRef utf8;
+
+ /* Print out a prompt to user that entry is desired */
+ if (is_user_prompt) {
+ if (defaultValue != NULL) {
+ SCPrint(TRUE, stdout, CFSTR("%@ [%@]: "), prompt, defaultValue);
+ } else {
+ SCPrint(TRUE, stdout, CFSTR("%@: "), prompt);
+ }
+ }
+
+ /* Get user input */
+ if (fgets(buf, sizeof(buf), stdin) == NULL) {
+ return NULL;
+ }
+
+ /* Prepare for trim */
+ len = (int)strlen(buf);
+ modbuf = buf;
+ modlen = len;
+
+ /* Trim new-line */
+ if ((modlen > 0) && (modbuf[modlen - 1] == '\n')) {
+ modbuf[modlen - 1] = '\0';
+ modlen--;
+ }
+
+ /* If nothing was entered at the user prompt, set default */
+ if (is_user_prompt && defaultValue != NULL && modlen == 0) {
+ CFRetain(defaultValue);
+ return defaultValue;
+ }
+
+ /* Trim spaces from front */
+ while (modlen > 0 && isspace(modbuf[0])) {
+ modbuf = &modbuf[1];
+ modlen--;
+ }
+
+ /* Trim spaces from back */
+ for (i = modlen - 1; i >= 0; i--) {
+ if (isspace(buf[i])) {
+ buf[i] = '\0';
+ modlen--;
+ } else {
+ break;
+ }
+ }
+
+ utf8 = CFStringCreateWithBytes(NULL, (UInt8 *)modbuf, modlen, kCFStringEncodingUTF8, TRUE);
+ return utf8;
+}
+
static char *
getLine(char *buf, int len, InputRef src)
{
if (line == NULL)
return NULL;
- strncpy(buf, line, len);
+ strlcpy(buf, line, len);
} else {
if (fgets(buf, len, src->fp) == NULL)
return NULL;
}
- n = strlen(buf);
+ n = (int)strlen(buf);
if (buf[n-1] == '\n') {
/* the entire line fit in the buffer, remove the newline */
buf[n-1] = '\0';
} while ((n != '\n') && (n != EOF));
}
- if (src->h) {
+ if (src->h && (buf[0] != '\0')) {
HistEvent ev;
history(src->h, &ev, H_ENTER, buf);
}
-
return buf;
}
SCPrint(TRUE, stderr, CFSTR("usage: %s\n"), command);
SCPrint(TRUE, stderr, CFSTR("\tinteractive access to the dynamic store.\n"));
SCPrint(TRUE, stderr, CFSTR("\n"));
- SCPrint(TRUE, stderr, CFSTR(" or: %s --prefs\n"), command);
+ SCPrint(TRUE, stderr, CFSTR(" or: %s --prefs [preference-file]\n"), command);
SCPrint(TRUE, stderr, CFSTR("\tinteractive access to the [raw] stored preferences.\n"));
SCPrint(TRUE, stderr, CFSTR("\n"));
- SCPrint(TRUE, stderr, CFSTR(" or: %s -r nodename\n"), command);
- SCPrint(TRUE, stderr, CFSTR(" or: %s -r address\n"), command);
- SCPrint(TRUE, stderr, CFSTR(" or: %s -r local-address remote-address\n"), command);
- SCPrint(TRUE, stderr, CFSTR("\tcheck reachability of node, address, or address pair.\n"));
+ SCPrint(TRUE, stderr, CFSTR(" or: %s [-W] -r nodename\n"), command);
+ SCPrint(TRUE, stderr, CFSTR(" or: %s [-W] -r address\n"), command);
+ SCPrint(TRUE, stderr, CFSTR(" or: %s [-W] -r local-address remote-address\n"), command);
+ SCPrint(TRUE, stderr, CFSTR("\tcheck reachability of node, address, or address pair (-W to \"watch\").\n"));
SCPrint(TRUE, stderr, CFSTR("\n"));
SCPrint(TRUE, stderr, CFSTR(" or: %s -w dynamic-store-key [ -t timeout ]\n"), command);
SCPrint(TRUE, stderr, CFSTR("\t-w\twait for presense of dynamic store key\n"));
SCPrint(TRUE, stderr, CFSTR("\n"));
SCPrint(TRUE, stderr, CFSTR(" or: %s --get pref\n"), command);
SCPrint(TRUE, stderr, CFSTR(" or: %s --set pref [newval]\n"), command);
+ SCPrint(TRUE, stderr, CFSTR(" or: %s --get filename path key \n"), command);
SCPrint(TRUE, stderr, CFSTR("\tpref\tdisplay (or set) the specified preference. Valid preferences\n"));
SCPrint(TRUE, stderr, CFSTR("\t\tinclude:\n"));
SCPrint(TRUE, stderr, CFSTR("\t\t\tComputerName, LocalHostName, HostName\n"));
SCPrint(TRUE, stderr, CFSTR("\n"));
SCPrint(TRUE, stderr, CFSTR(" or: %s --proxy\n"), command);
SCPrint(TRUE, stderr, CFSTR("\tshow \"proxy\" configuration.\n"));
+ SCPrint(TRUE, stderr, CFSTR("\n"));
+ SCPrint(TRUE, stderr, CFSTR(" or: %s --nwi\n"), command);
+ SCPrint(TRUE, stderr, CFSTR("\tshow network information\n"));
+ SCPrint(TRUE, stderr, CFSTR("\n"));
+ SCPrint(TRUE, stderr, CFSTR(" or: %s --nc\n"), command);
+ SCPrint(TRUE, stderr, CFSTR("\tshow VPN network configuration information. Use --nc help for full command list\n"));
+
+ if (_sc_debug) {
+ SCPrint(TRUE, stderr, CFSTR("\n"));
+ SCPrint(TRUE, stderr, CFSTR(" or: %s --log IPMonitor [off|on]\n"), command);
+ SCPrint(TRUE, stderr, CFSTR("\tmanage logging.\n"));
+
+ SCPrint(TRUE, stderr, CFSTR("\n"));
+ SCPrint(TRUE, stderr, CFSTR(" or: %s --disable-until-needed <interfaceName> [on|off ]\n"), command);
+ SCPrint(TRUE, stderr, CFSTR("\tmanage secondary interface demand.\n"));
+ }
+
+#if !TARGET_OS_IPHONE
+ SCPrint(TRUE, stderr, CFSTR("\n"));
+ SCPrint(TRUE, stderr, CFSTR(" or: %s --allow-new-interfaces [off|on]\n"), command);
+ SCPrint(TRUE, stderr, CFSTR("\tmanage new interface creation with screen locked.\n"));
+#endif // !TARGET_OS_IPHONE
if (getenv("ENABLE_EXPERIMENTAL_SCUTIL_COMMANDS")) {
SCPrint(TRUE, stderr, CFSTR("\n"));
SCPrint(TRUE, stderr, CFSTR("\tmanage network configuration.\n"));
}
+ SCPrint(TRUE, stderr, CFSTR("\n"));
+ SCPrint(TRUE, stderr, CFSTR(" or: %s --error err#\n"), command);
+ SCPrint(TRUE, stderr, CFSTR("\tdisplay a descriptive message for the given error code\n"));
+
exit (EX_USAGE);
}
static char *
prompt(EditLine *el)
{
+#pragma unused(el)
+#if !TARGET_OS_SIMULATOR
return "> ";
+#else // !TARGET_OS_SIMULATOR
+ return "sim> ";
+#endif // !TARGET_OS_SIMULATOR
}
int
main(int argc, char * const argv[])
{
- Boolean doDNS = FALSE;
- Boolean doNet = FALSE;
- Boolean doPrefs = FALSE;
- Boolean doProxy = FALSE;
- Boolean doReach = FALSE;
- char *get = NULL;
+ const char * advisoryInterface = NULL;
+#if !TARGET_OS_IPHONE
+ Boolean allowNewInterfaces = FALSE;
+#endif // !TARGET_OS_IPHONE
+ Boolean configuration = FALSE;
+ Boolean disableUntilNeeded = FALSE;
+ Boolean doAdvisory = FALSE;
+ Boolean doDNS = FALSE;
+ Boolean doNet = FALSE;
+ Boolean doNWI = FALSE;
+ Boolean doPrefs = FALSE;
+ Boolean doProxy = FALSE;
+ Boolean doReach = FALSE;
+ Boolean doSnap = FALSE;
+ char *error = NULL;
+ char *get = NULL;
+ char *log = NULL;
extern int optind;
int opt;
int opti;
- const char *prog = argv[0];
- char *set = NULL;
+ const char *prog = argv[0];
+ char *renew = NULL;
+ char *set = NULL;
+ char *nc_cmd = NULL;
InputRef src;
- int timeout = 15; /* default timeout (in seconds) */
- char *wait = NULL;
- int xStore = 0; /* non dynamic store command line options */
+ int timeout = 15; /* default timeout (in seconds) */
+ char *wait = NULL;
+ Boolean watch = FALSE;
+ int xStore = 0; /* non dynamic store command line options */
/* process any arguments */
- while ((opt = getopt_long(argc, argv, "dvprt:w:", longopts, &opti)) != -1)
+ while ((opt = getopt_long(argc, argv, "dDvprt:w:W", longopts, &opti)) != -1) {
switch(opt) {
case 'd':
_sc_debug = TRUE;
- _sc_log = FALSE; /* enable framework logging */
+ _sc_log = kSCLogDestinationFile; /* enable framework logging */
+ break;
+ case 'D':
+ doDispatch = TRUE;
break;
case 'v':
_sc_verbose = TRUE;
- _sc_log = FALSE; /* enable framework logging */
+ _sc_log = kSCLogDestinationFile; /* enable framework logging */
break;
case 'p':
enablePrivateAPI = TRUE;
wait = optarg;
xStore++;
break;
+ case 'W':
+ watch = TRUE;
+ break;
case 0:
- if (strcmp(longopts[opti].name, "dns") == 0) {
+ if (strcmp(longopts[opti].name, "configuration") == 0) {
+ configuration = TRUE;
+ xStore++;
+ } else if (strcmp(longopts[opti].name, "dns") == 0) {
doDNS = TRUE;
xStore++;
+ } else if (strcmp(longopts[opti].name, "error") == 0) {
+ error = optarg;
+ xStore++;
} else if (strcmp(longopts[opti].name, "get") == 0) {
get = optarg;
xStore++;
+ } else if (strcmp(longopts[opti].name, "nc") == 0) {
+ nc_cmd = optarg;
+ xStore++;
} else if (strcmp(longopts[opti].name, "net") == 0) {
doNet = TRUE;
xStore++;
+ } else if (strcmp(longopts[opti].name, "nwi") == 0) {
+ doNWI = TRUE;
+ xStore++;
} else if (strcmp(longopts[opti].name, "prefs") == 0) {
doPrefs = TRUE;
xStore++;
} else if (strcmp(longopts[opti].name, "proxy") == 0) {
doProxy = TRUE;
xStore++;
+ } else if (strcmp(longopts[opti].name, "renew") == 0) {
+ renew = optarg;
+ xStore++;
} else if (strcmp(longopts[opti].name, "set") == 0) {
set = optarg;
xStore++;
+ } else if (strcmp(longopts[opti].name, "snapshot") == 0) {
+ doSnap = TRUE;
+ xStore++;
+ } else if (strcmp(longopts[opti].name, "log") == 0) {
+ log = optarg;
+ xStore++;
+#if !TARGET_OS_IPHONE
+ } else if (strcmp(longopts[opti].name, "allow-new-interfaces") == 0) {
+ allowNewInterfaces = TRUE;
+ xStore++;
+#endif // !TARGET_OS_IPHONE
+ } else if (strcmp(longopts[opti].name, "disable-until-needed") == 0) {
+ disableUntilNeeded = TRUE;
+ xStore++;
+ } else if (strcmp(longopts[opti].name, "user") == 0) {
+ username = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingUTF8);
+ } else if (strcmp(longopts[opti].name, "password") == 0) {
+ password = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingUTF8);
+ } else if (strcmp(longopts[opti].name, "secret") == 0) {
+ sharedsecret = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingUTF8);
+ } else if (strcmp(longopts[opti].name, "advisory") == 0) {
+ doAdvisory = TRUE;
+ advisoryInterface = optarg;
+ xStore++;
}
break;
case '?':
default :
usage(prog);
}
+ }
+
argc -= optind;
argv += optind;
usage(prog);
}
- /* are we checking the reachability of a host/address */
+ /* are we asking for a configuration summary */
+ if (configuration) {
+ do_configuration(argc, (char **)argv);
+ /* NOT REACHED */
+ }
+
+ /* are we checking (or watching) the reachability of a host/address */
if (doReach) {
- if ((argc < 1) || (argc > 2)) {
+ if (argc < 1) {
usage(prog);
}
- do_checkReachability(argc, (char **)argv);
+ if (watch) {
+ do_watchReachability(argc, (char **)argv);
+ } else {
+ do_checkReachability(argc, (char **)argv);
+ }
/* NOT REACHED */
}
/* are we looking up the DNS configuration */
if (doDNS) {
- do_showDNSConfiguration(argc, (char **)argv);
+ if (watch) {
+ do_watchDNSConfiguration(argc, (char **)argv);
+ } else {
+ do_showDNSConfiguration(argc, (char **)argv);
+ }
+ /* NOT REACHED */
+ }
+
+ if (doNWI) {
+ if (watch) {
+ do_watchNWI(argc, (char**)argv);
+ } else {
+ do_showNWI(argc, (char**)argv);
+ }
/* NOT REACHED */
}
+ if (doSnap) {
+ if (!enablePrivateAPI) {
+ usage(prog);
+ }
+
+ do_open(0, NULL); /* open the dynamic store */
+ do_snapshot(argc, (char**)argv);
+ exit(0);
+ }
+
+ if (doAdvisory) {
+ do_advisory(advisoryInterface, watch, argc, (char**)argv);
+ /* NOT REACHED */
+ }
+
+ /* are we translating error #'s to descriptive text */
+ if (error != NULL) {
+ int sc_status = atoi(error);
+
+ SCPrint(TRUE, stdout, CFSTR("Error: 0x%08x %d %s\n"),
+ sc_status,
+ sc_status,
+ SCErrorString(sc_status));
+ exit(0);
+ }
+
/* are we looking up a preference value */
if (get) {
- if (findPref(get) < 0) {
+ if (argc == 0) {
+ if (findPref(get) < 0) {
+ usage(prog);
+ }
+ } else if (argc == 2) {
+ /*
+ * extended --get
+ * i.e. scutil --get <filename> <prefs path> <key>
+ *
+ * need to go back one argument to re-use the 1st "--get"
+ * argument as the prefs path name
+ */
+ argc++;
+ argv--;
+ } else {
usage(prog);
}
+
do_getPref(get, argc, (char **)argv);
/* NOT REACHED */
}
/* NOT REACHED */
}
+ /* verbose log */
+ if (log != NULL) {
+ if (strcasecmp(log, "IPMonitor")) {
+ usage(prog);
+ }
+ do_log(log, argc, (char * *)argv);
+ /* NOT REACHED */
+ }
+
+#if !TARGET_OS_IPHONE
+ /* allowNewInterfaces */
+ if (allowNewInterfaces) {
+ do_ifnamer("allow-new-interfaces", argc, (char * *)argv);
+ /* NOT REACHED */
+ }
+#endif // !TARGET_OS_IPHONE
+
+ /* disableUntilNeeded */
+ if (disableUntilNeeded) {
+ do_disable_until_needed(argc, (char * *)argv);
+ /* NOT REACHED */
+ }
+
+ /* network connection commands */
+ if (nc_cmd) {
+ if (find_nc_cmd(nc_cmd) < 0) {
+ usage(prog);
+ }
+ do_nc_cmd(nc_cmd, argc, (char **)argv, watch);
+ /* NOT REACHED */
+ }
+
if (doNet) {
/* if we are going to be managing the network configuration */
commands = (cmdInfo *)commands_net;
usage(prog);
}
- do_net_init(); /* initialization */
- do_net_open(0, NULL); /* open default prefs */
+ do_net_init(); /* initialization */
+ do_net_open(argc, (char **)argv); /* open prefs */
} else if (doPrefs) {
/* if we are going to be managing the network configuration */
commands = (cmdInfo *)commands_prefs;
nCommands = nCommands_prefs;
- do_dictInit(0, NULL); /* start with an empty dictionary */
- do_prefs_init(); /* initialization */
- do_prefs_open(0, NULL); /* open default prefs */
+ do_dictInit(0, NULL); /* start with an empty dictionary */
+ do_prefs_init(); /* initialization */
+ do_prefs_open(argc, (char **)argv); /* open prefs */
} else {
/* if we are going to be managing the dynamic store */
commands = (cmdInfo *)commands_store;
do_open(0, NULL); /* open the dynamic store */
}
+ /* are we trying to renew a DHCP lease */
+ if (renew != NULL) {
+ do_renew(renew);
+ /* NOT REACHED */
+ }
+
/* allocate command input stream */
src = (InputRef)CFAllocatorAllocate(NULL, sizeof(Input), 0);
src->fp = stdin;
}
}
- while (process_line(src) == TRUE) {
- /* debug information, diagnostics */
- __showMachPortStatus();
+ while (TRUE) {
+ Boolean ok;
+
+ ok = process_line(src);
+ if (!ok) {
+ break;
+ }
}
/* close the socket, free resources */