+#pragma mark -
+#pragma mark VPN options
+
+
+static int
+__doVPNAuthPW(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
+{
+ CFStringRef encryptionType;
+
+ if (argc < 1) {
+ SCPrint(TRUE, stdout, CFSTR("VPN password not specified\n"));
+ return -1;
+ }
+
+ encryptionType = CFDictionaryGetValue(newConfiguration, kSCPropNetVPNAuthPasswordEncryption);
+ if (strlen(argv[0]) > 0) {
+ if (encryptionType == NULL) {
+#ifdef INLINE_PASSWORDS_USE_CFSTRING
+ CFStringRef pw;
+
+ pw = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
+#else // INLINE_PASSWORDS_USE_CFSTRING
+ CFIndex n;
+ CFMutableDataRef pw;
+ CFStringRef str;
+
+ str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
+ n = CFStringGetLength(str);
+ pw = CFDataCreateMutable(NULL, n * sizeof(UniChar));
+ CFDataSetLength(pw, n * sizeof(UniChar));
+ CFStringGetCharacters(str,
+ CFRangeMake(0, n),
+ (UniChar *)(void *)CFDataGetMutableBytePtr(pw));
+ CFRelease(str);
+#endif // INLINE_PASSWORDS_USE_CFSTRING
+
+ CFDictionarySetValue(newConfiguration, key, pw);
+ CFRelease(pw);
+ } else if (CFEqual(encryptionType, kSCValNetVPNAuthPasswordEncryptionKeychain)) {
+ Boolean ok;
+ CFDataRef pw;
+ CFStringRef str;
+
+ str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
+ pw = CFStringCreateExternalRepresentation(NULL, str, kCFStringEncodingUTF8, 0);
+ ok = SCNetworkInterfaceSetPassword(net_interface,
+ kSCNetworkInterfacePasswordTypeVPN,
+ pw,
+ NULL);
+ CFRelease(pw);
+ CFRelease(str);
+ if (ok) {
+ updateInterfaceConfiguration(newConfiguration);
+ } else {
+ return -1;
+ }
+ } else {
+ SCPrint(TRUE, stdout, CFSTR("VPN password type \"%@\" not supported\n"), encryptionType);
+ return -1;
+ }
+ } else {
+ if (encryptionType == NULL) {
+ CFDictionaryRemoveValue(newConfiguration, key);
+ } else if (CFEqual(encryptionType, kSCValNetVPNAuthPasswordEncryptionKeychain)) {
+ Boolean ok;
+
+ ok = SCNetworkInterfaceRemovePassword(net_interface, kSCNetworkInterfacePasswordTypeVPN);
+ if (ok) {
+ updateInterfaceConfiguration(newConfiguration);
+ } else {
+ return -1;
+ }
+ } else {
+ SCPrint(TRUE, stdout, CFSTR("PPP password type \"%@\" not supported\n"), encryptionType);
+ return -1;
+ }
+ }
+
+ return 1;
+}
+
+
+static int
+__doVPNAuthPWType(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration)
+{
+ if (argc < 1) {
+ SCPrint(TRUE, stdout, CFSTR("VPN password type mode not specified\n"));
+ return -1;
+ }
+
+ if (strlen(argv[0]) > 0) {
+ if (strcasecmp(argv[0], "keychain") == 0) {
+ CFDictionarySetValue(newConfiguration, key, kSCValNetVPNAuthPasswordEncryptionKeychain);
+ } else if (strcasecmp(argv[0], "prompt") == 0) {
+ CFDictionarySetValue(newConfiguration, key, kSCValNetVPNAuthPasswordEncryptionPrompt);
+ } else {
+ SCPrint(TRUE, stdout, CFSTR("invalid password type\n"));
+ return -1;
+ }
+ } else {
+ CFDictionaryRemoveValue(newConfiguration, key);
+ }
+
+ // encryption type changed, reset password
+ CFDictionaryRemoveValue(newConfiguration, kSCPropNetVPNAuthPassword);
+
+ return 1;
+}
+
+
+static selections vpnAuthenticationMethodSelections[] = {
+ { CFSTR("Password") , &kSCValNetVPNAuthenticationMethodPassword , 0 },
+ { CFSTR("Certificate") , &kSCValNetVPNAuthenticationMethodCertificate , 0 },
+ { NULL , NULL , 0 }
+};
+
+
+static options vpnOptions[] = {
+ { "AuthName" , "account" , isString , &kSCPropNetVPNAuthName , NULL , NULL },
+ { "Account" , "account" , isString , &kSCPropNetVPNAuthName , NULL , NULL },
+ { "AuthPassword" , "password" , isOther , &kSCPropNetVPNAuthPassword , __doVPNAuthPW , NULL },
+ { "Password" , "password" , isOther , &kSCPropNetVPNAuthPassword , __doVPNAuthPW , NULL },
+ { "AuthPasswordEncryption" , "type" , isOther , &kSCPropNetVPNAuthPasswordEncryption , __doVPNAuthPWType , NULL },
+ { "AuthenticationMethod" , NULL , isChooseOne , &kSCPropNetVPNAuthenticationMethod , NULL , (void *)vpnAuthenticationMethodSelections },
+ { "ConnectTime" , "?time" , isNumber , &kSCPropNetVPNConnectTime , NULL , NULL },
+ { "DisconnectOnFastUserSwitch", NULL , isBoolean , &kSCPropNetVPNDisconnectOnFastUserSwitch, NULL , NULL },
+ { "DisconnectOnIdle" , NULL , isBoolean , &kSCPropNetVPNDisconnectOnIdle , NULL , NULL },
+ { "DisconnectOnIdleTimer" , "timeout" , isNumber , &kSCPropNetVPNDisconnectOnIdleTimer , NULL , NULL },
+ { "DisconnectOnLogout" , NULL , isBoolean , &kSCPropNetVPNDisconnectOnLogout , NULL , NULL },
+ { "DisconnectOnSleep" , NULL , isBoolean , &kSCPropNetVPNDisconnectOnSleep , NULL , NULL },
+ { "Logfile" , "path" , isString , &kSCPropNetVPNLogfile , NULL , NULL },
+ { "MTU" , NULL , isNumber , &kSCPropNetVPNMTU , NULL , NULL },
+ { "RemoteAddress" , "server" , isString , &kSCPropNetVPNRemoteAddress , NULL , NULL },
+ { "Server" , "server" , isString , &kSCPropNetVPNRemoteAddress , NULL , NULL },
+ { "VerboseLogging" , NULL , isBoolean , &kSCPropNetVPNVerboseLogging , NULL , NULL },
+
+ // --- Help ---
+ { "?" , NULL , isHelp , NULL , NULL ,
+ "\nVPN configuration commands\n\n"
+ " set interface [Server server]\n"
+ " set interface [Account account]\n"
+ " set interface [Password password]\n"
+ }
+};
+#define N_VPN_OPTIONS (sizeof(vpnOptions) / sizeof(vpnOptions[0]))
+
+
+static Boolean
+set_interface_vpn(int argc, char **argv, CFMutableDictionaryRef newConfiguration)
+{
+ Boolean ok;
+
+ ok = _process_options(vpnOptions, N_VPN_OPTIONS, argc, argv, newConfiguration);
+ return ok;
+}