]> git.saurik.com Git - apple/configd.git/blobdiff - SystemConfiguration.fproj/SCNetworkConnectionPrivate.c
configd-204.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCNetworkConnectionPrivate.c
diff --git a/SystemConfiguration.fproj/SCNetworkConnectionPrivate.c b/SystemConfiguration.fproj/SCNetworkConnectionPrivate.c
new file mode 100644 (file)
index 0000000..56c444f
--- /dev/null
@@ -0,0 +1,1758 @@
+/*
+ * Copyright (c) 2006, 2007 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,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * 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@
+ */
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreFoundation/CFRuntime.h>
+#include <SystemConfiguration/SystemConfiguration.h>
+#include <SystemConfiguration/SCPrivate.h>             // for SCLog
+#include "SCNetworkConfigurationInternal.h"
+#include <notify.h>
+#include <pthread.h>
+#include <ppp/PPPControllerPriv.h>
+
+
+#pragma mark -
+#pragma mark SCUserPreferences
+
+
+typedef struct {
+
+       // base CFType information
+       CFRuntimeBase           cfBase;
+
+       // serviceID
+       CFStringRef             serviceID;
+
+       // user preferences [unique] id
+       CFStringRef             prefsID;
+
+} SCUserPreferencesPrivate, *SCUserPreferencesPrivateRef;
+
+
+static CFStringRef     __SCUserPreferencesCopyDescription      (CFTypeRef cf);
+static void            __SCUserPreferencesDeallocate           (CFTypeRef cf);
+static Boolean         __SCUserPreferencesEqual                (CFTypeRef cf1, CFTypeRef cf2);
+static CFHashCode      __SCUserPreferencesHash                 (CFTypeRef cf);
+
+
+static CFTypeID __kSCUserPreferencesTypeID     = _kCFRuntimeNotATypeID;
+
+
+static const CFRuntimeClass __SCUserPreferencesClass = {
+       0,                                      // version
+       "SCUserPreferences",                    // className
+       NULL,                                   // init
+       NULL,                                   // copy
+       __SCUserPreferencesDeallocate,          // dealloc
+       __SCUserPreferencesEqual,               // equal
+       __SCUserPreferencesHash,                // hash
+       NULL,                                   // copyFormattingDesc
+       __SCUserPreferencesCopyDescription      // copyDebugDesc
+};
+
+
+static pthread_once_t          initialized     = PTHREAD_ONCE_INIT;
+
+
+static CFStringRef
+__SCUserPreferencesCopyDescription(CFTypeRef cf)
+{
+       CFAllocatorRef                  allocator       = CFGetAllocator(cf);
+       CFMutableStringRef              result;
+       SCUserPreferencesPrivateRef     prefsPrivate    = (SCUserPreferencesPrivateRef)cf;
+
+       result = CFStringCreateMutable(allocator, 0);
+       CFStringAppendFormat(result, NULL, CFSTR("<SCUserPreferences %p [%p]> {"), cf, allocator);
+       CFStringAppendFormat(result, NULL, CFSTR("service = %@"), prefsPrivate->serviceID);
+       CFStringAppendFormat(result, NULL, CFSTR(", id = %@"), prefsPrivate->prefsID);
+       CFStringAppendFormat(result, NULL, CFSTR("}"));
+
+       return result;
+}
+
+
+static void
+__SCUserPreferencesDeallocate(CFTypeRef cf)
+{
+       SCUserPreferencesPrivateRef     prefsPrivate    = (SCUserPreferencesPrivateRef)cf;
+
+       /* release resources */
+
+       CFRelease(prefsPrivate->prefsID);
+       CFRelease(prefsPrivate->serviceID);
+
+       return;
+}
+
+
+static Boolean
+__SCUserPreferencesEqual(CFTypeRef cf1, CFTypeRef cf2)
+{
+       SCUserPreferencesPrivateRef     s1      = (SCUserPreferencesPrivateRef)cf1;
+       SCUserPreferencesPrivateRef     s2      = (SCUserPreferencesPrivateRef)cf2;
+
+       if (s1 == s2)
+               return TRUE;
+
+       if (!CFEqual(s1->prefsID, s2->prefsID))
+               return FALSE;   // if not the same [unique] prefs identifier
+
+       return TRUE;
+}
+
+
+static CFHashCode
+__SCUserPreferencesHash(CFTypeRef cf)
+{
+       SCUserPreferencesPrivateRef     prefsPrivate    = (SCUserPreferencesPrivateRef)cf;
+
+       return CFHash(prefsPrivate->prefsID);
+}
+
+
+static void
+__SCUserPreferencesInitialize(void)
+{
+       __kSCUserPreferencesTypeID = _CFRuntimeRegisterClass(&__SCUserPreferencesClass);
+       return;
+}
+
+
+static SCUserPreferencesPrivateRef
+__SCUserPreferencesCreatePrivate(CFAllocatorRef                allocator,
+                                CFStringRef            serviceID,
+                                CFStringRef            prefsID)
+{
+       SCUserPreferencesPrivateRef     prefsPrivate;
+       uint32_t                        size;
+
+       /* initialize runtime */
+       pthread_once(&initialized, __SCUserPreferencesInitialize);
+
+       /* allocate target */
+       size         = sizeof(SCUserPreferencesPrivate) - sizeof(CFRuntimeBase);
+       prefsPrivate = (SCUserPreferencesPrivateRef)_CFRuntimeCreateInstance(allocator,
+                                                                            __kSCUserPreferencesTypeID,
+                                                                            size,
+                                                                            NULL);
+       if (prefsPrivate == NULL) {
+               return NULL;
+       }
+
+       prefsPrivate->serviceID = CFStringCreateCopy(NULL, serviceID);
+       prefsPrivate->prefsID   = CFStringCreateCopy(NULL, prefsID);
+
+       return prefsPrivate;
+}
+
+
+static __inline__ CFTypeRef
+isA_SCUserPreferences(CFTypeRef obj)
+{
+       return (isA_CFType(obj, SCUserPreferencesGetTypeID()));
+}
+
+
+#pragma mark -
+#pragma mark SCUserPreferences SPIs
+
+
+#define        USER_PREFERENCES_NOTIFICATION   "com.apple.networkConnect"
+#define        USER_PREFERENCES_APPLICATION_ID CFSTR("com.apple.networkConnect")
+#define        USER_PREFERENCES_ID             CFSTR("UniqueIdentifier")
+#define        USER_PREFERENCES_DEFAULT        CFSTR("ConnectByDefault")
+
+
+static CFArrayRef
+copyCFPreferencesForServiceID(CFStringRef serviceID)
+{
+       CFArrayRef      prefs;
+
+       // fetch "Managed" or "ByHost" user preferences
+       (void) CFPreferencesAppSynchronize(USER_PREFERENCES_APPLICATION_ID);
+       prefs = CFPreferencesCopyAppValue(serviceID,
+                                         USER_PREFERENCES_APPLICATION_ID);
+
+       if ((prefs != NULL) && !isA_CFArray(prefs)) {
+               CFRelease(prefs);
+               return NULL;
+       }
+
+       return prefs;
+}
+
+
+static Boolean
+setCFPreferencesForServiceID(CFStringRef serviceID, CFArrayRef newPreferences)
+{
+       Boolean ok;
+
+       if (CFPreferencesAppValueIsForced(serviceID, USER_PREFERENCES_APPLICATION_ID)) {
+               return FALSE;
+       }
+
+       CFPreferencesSetValue(serviceID,
+                             newPreferences,
+                             USER_PREFERENCES_APPLICATION_ID,
+                             kCFPreferencesCurrentUser,
+                             kCFPreferencesCurrentHost);
+       ok = CFPreferencesSynchronize(USER_PREFERENCES_APPLICATION_ID,
+                                     kCFPreferencesCurrentUser,
+                                     kCFPreferencesCurrentHost);
+
+       (void) notify_post(USER_PREFERENCES_NOTIFICATION);
+
+       return ok;
+}
+
+
+static void
+addPreference(CFMutableArrayRef *newPrefs, CFDictionaryRef newDict)
+{
+       if (*newPrefs == NULL) {
+               *newPrefs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+       }
+       CFArrayAppendValue(*newPrefs, newDict);
+
+       return;
+}
+
+
+typedef CFDictionaryRef (*processPreferencesCallout)   (CFStringRef            serviceID,
+                                                        CFDictionaryRef        current,
+                                                        void                   *context1,
+                                                        void                   *context2,
+                                                        void                   *context3);
+
+
+static Boolean
+processPreferences(CFStringRef                 serviceID,
+                  processPreferencesCallout    callout,
+                  void                         *context1,
+                  void                         *context2,
+                  void                         *context3)
+{
+       Boolean                         changed         = FALSE;
+       CFIndex                         i;
+       CFIndex                         n;
+       CFDictionaryRef                 newDict         = NULL;
+       CFMutableArrayRef               newPrefs        = NULL;
+       Boolean                         ok              = TRUE;
+       CFArrayRef                      prefs;
+
+       prefs = copyCFPreferencesForServiceID(serviceID);
+       n = (prefs != NULL) ? CFArrayGetCount(prefs) : 0;
+       for (i = 0; i < n; i++) {
+               CFDictionaryRef dict;
+
+               dict = CFArrayGetValueAtIndex(prefs, i);
+               if (isA_CFDictionary(dict)) {
+                       newDict = (*callout)(serviceID, dict, context1, context2, context3);
+                       if (newDict == NULL) {
+                               // if entry to be removed
+                               changed = TRUE;
+                               continue;
+                       }
+               } else {
+                       // if not a CFDictionary, leave as-is
+                       newDict = CFRetain(dict);
+               }
+
+               if (!CFEqual(dict, newDict)) {
+                       changed = TRUE;
+               }
+
+               addPreference(&newPrefs, newDict);
+               CFRelease(newDict);
+       }
+       if (prefs != NULL) CFRelease(prefs);
+
+       newDict = (*callout)(serviceID, NULL, context1, context2, context3);
+       if (newDict != NULL) {
+               // if new entry
+               changed = TRUE;
+               addPreference(&newPrefs, newDict);
+               CFRelease(newDict);
+       }
+
+       if (changed) {
+               ok = setCFPreferencesForServiceID(serviceID, newPrefs);
+       }
+       if (newPrefs != NULL) CFRelease(newPrefs);
+
+       return ok;
+}
+
+
+static __inline__ Boolean
+isMatchingPrefsID(CFDictionaryRef dict, CFStringRef matchID)
+{
+       CFStringRef     prefsID;
+
+       prefsID = CFDictionaryGetValue(dict, USER_PREFERENCES_ID);
+       if (isA_CFString(prefsID)) {
+               if (CFEqual(prefsID, matchID)) {
+                       return TRUE;
+               }
+       }
+
+       return FALSE;
+}
+
+
+CFTypeID
+SCUserPreferencesGetTypeID(void)
+{
+       pthread_once(&initialized, __SCUserPreferencesInitialize);      /* initialize runtime */
+       return __kSCUserPreferencesTypeID;
+}
+
+
+CFStringRef
+SCUserPreferencesGetUniqueID(SCUserPreferencesRef userPreferences)
+{
+       SCUserPreferencesPrivateRef     userPrivate     = (SCUserPreferencesPrivateRef)userPreferences;
+
+       if (!isA_SCUserPreferences(userPreferences)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
+       return userPrivate->prefsID;
+}
+
+
+Boolean
+SCUserPreferencesIsForced(SCUserPreferencesRef userPreferences)
+{
+       SCUserPreferencesPrivateRef     userPrivate     = (SCUserPreferencesPrivateRef)userPreferences;
+
+       if (!isA_SCUserPreferences(userPreferences)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
+       return CFPreferencesAppValueIsForced(userPrivate->serviceID, USER_PREFERENCES_APPLICATION_ID);
+}
+
+
+static CFDictionaryRef
+removeCallout(CFStringRef      serviceID,
+             CFDictionaryRef   current,
+             void              *context1,
+             void              *context2,
+             void              *context3)
+{
+       CFStringRef     matchID = (CFStringRef)context1;
+
+       if (current == NULL) {
+               // we have nothing to "add"
+               return NULL;
+       }
+
+       if (isMatchingPrefsID(current, matchID)) {
+               // if we match, don't add (i.e. remove)
+               return NULL;
+       }
+
+       return CFRetain(current);
+}
+
+
+Boolean
+SCUserPreferencesRemove(SCUserPreferencesRef userPreferences)
+{
+       SCUserPreferencesPrivateRef     userPrivate     = (SCUserPreferencesPrivateRef)userPreferences;
+
+       if (!isA_SCUserPreferences(userPreferences)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
+       return processPreferences(userPrivate->serviceID,
+                                 removeCallout,
+                                 (void *)userPrivate->prefsID,
+                                 NULL,
+                                 NULL);
+}
+
+
+static CFDictionaryRef
+setCurrentCallout(CFStringRef          serviceID,
+                 CFDictionaryRef       current,
+                 void                  *context1,
+                 void                  *context2,
+                 void                  *context3)
+{
+       CFStringRef                     matchID         = (CFStringRef)context1;
+       CFMutableDictionaryRef          newDict;
+
+       if (current == NULL) {
+               // we have nothing to "add"
+               return NULL;
+       }
+
+       newDict = CFDictionaryCreateMutableCopy(NULL, 0, current);
+
+       // remove "default" flag
+       CFDictionaryRemoveValue(newDict, USER_PREFERENCES_DEFAULT);
+
+       if (isMatchingPrefsID(current, matchID)) {
+               // if we match, set "default" flag
+               CFDictionarySetValue(newDict, USER_PREFERENCES_DEFAULT, kCFBooleanTrue);
+       }
+
+       return newDict;
+}
+
+
+Boolean
+SCUserPreferencesSetCurrent(SCUserPreferencesRef userPreferences)
+{
+       SCUserPreferencesPrivateRef     userPrivate     = (SCUserPreferencesPrivateRef)userPreferences;
+
+       if (!isA_SCUserPreferences(userPreferences)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
+       return processPreferences(userPrivate->serviceID,
+                                 setCurrentCallout,
+                                 (void *)userPrivate->prefsID,
+                                 NULL,
+                                 NULL);
+}
+
+
+static CFDictionaryRef
+copyNameCallout(CFStringRef    serviceID,
+               CFDictionaryRef current,
+               void            *context1,
+               void            *context2,
+               void            *context3)
+{
+       CFStringRef     matchID = (CFStringRef)context1;
+       CFStringRef     *name   = (CFStringRef *)context3;
+
+       if (current == NULL) {
+               // we have nothing to "add"
+               return NULL;
+       }
+
+       if (isMatchingPrefsID(current, matchID)) {
+               *name = CFDictionaryGetValue(current, kSCPropUserDefinedName);
+
+               // for backwards compatibility, we also check for the name in the PPP entity
+               if (*name == NULL) {
+                       CFDictionaryRef ppp;
+
+                       ppp = CFDictionaryGetValue(current, kSCEntNetPPP);
+                       if (isA_CFDictionary(ppp)) {
+                               *name = CFDictionaryGetValue(ppp, kSCPropUserDefinedName);
+                       }
+               }
+
+               *name = isA_CFString(*name);
+               if (*name != NULL) {
+                       CFRetain(*name);
+               }
+       }
+
+       return CFRetain(current);
+}
+
+
+CFStringRef
+SCUserPreferencesCopyName(SCUserPreferencesRef userPreferences)
+{
+       CFStringRef                     name            = NULL;
+       Boolean                         ok;
+       SCUserPreferencesPrivateRef     userPrivate     = (SCUserPreferencesPrivateRef)userPreferences;
+
+       if (!isA_SCUserPreferences(userPreferences)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
+       // find SCUserPreferences and copy name
+       ok = processPreferences(userPrivate->serviceID,
+                               copyNameCallout,
+                               (void *)userPrivate->prefsID,
+                               NULL,
+                               (void *)&name);
+       if (!ok) {
+               if (name != NULL) {
+                       CFRelease(name);
+                       name = NULL;
+               }
+       }
+
+       return name;
+}
+
+
+static CFDictionaryRef
+setNameCallout(CFStringRef     serviceID,
+              CFDictionaryRef  current,
+              void             *context1,
+              void             *context2,
+              void             *context3)
+{
+       CFStringRef             matchID = (CFStringRef)context1;
+       CFMutableDictionaryRef  newDict;
+       CFStringRef             newName = (CFStringRef)context2;
+
+       if (current == NULL) {
+               // we have nothing to "add"
+               return NULL;
+       }
+
+       newDict = CFDictionaryCreateMutableCopy(NULL, 0, current);
+
+       if (isMatchingPrefsID(current, matchID)) {
+               CFDictionaryRef pppEntity;
+
+               // set the name
+               if (newName != NULL) {
+                       CFDictionarySetValue(newDict, kSCPropUserDefinedName, newName);
+               } else {
+                       CFDictionaryRemoveValue(newDict, kSCPropUserDefinedName);
+               }
+
+               // for backwards compatibility, we also set the name in the PPP entity
+               pppEntity = CFDictionaryGetValue(newDict, kSCEntNetPPP);
+               if (isA_CFDictionary(pppEntity)) {
+                       CFMutableDictionaryRef  newPPPEntity;
+
+                       newPPPEntity = CFDictionaryCreateMutableCopy(NULL, 0, pppEntity);
+                       if (newName != NULL) {
+                               CFDictionarySetValue(newPPPEntity, kSCPropUserDefinedName, newName);
+                       } else {
+                               CFDictionaryRemoveValue(newPPPEntity, kSCPropUserDefinedName);
+                       }
+                       CFDictionarySetValue(newDict, kSCEntNetPPP, newPPPEntity);
+                       CFRelease(newPPPEntity);
+               }
+       }
+
+       return newDict;
+}
+
+
+Boolean
+SCUserPreferencesSetName(SCUserPreferencesRef userPreferences, CFStringRef newName)
+{
+       Boolean                         ok;
+       SCUserPreferencesPrivateRef     userPrivate     = (SCUserPreferencesPrivateRef)userPreferences;
+
+       if (!isA_SCUserPreferences(userPreferences)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
+       if ((newName != NULL) && !isA_CFString(newName)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
+       // find SCUserPreferences and set name
+       ok = processPreferences(userPrivate->serviceID,
+                               setNameCallout,
+                               (void *)userPrivate->prefsID,
+                               (void *)newName,
+                               NULL);
+
+       return ok;
+}
+
+
+static CFDictionaryRef
+copyInterfaceConfigurationCallout(CFStringRef          serviceID,
+                                 CFDictionaryRef       current,
+                                 void                  *context1,
+                                 void                  *context2,
+                                 void                  *context3)
+{
+       CFDictionaryRef *dict           = (CFDictionaryRef *)context3;
+       CFStringRef     interfaceType   = (CFStringRef)context2;
+       CFStringRef     matchID         = (CFStringRef)context1;
+
+       if (current == NULL) {
+               // we have nothing to "add"
+               return NULL;
+       }
+
+       if (isMatchingPrefsID(current, matchID)) {
+               *dict = CFDictionaryGetValue(current, interfaceType);
+               *dict = isA_CFDictionary(*dict);
+               if (*dict != NULL) {
+                       CFRetain(*dict);
+               }
+       }
+
+       return CFRetain(current);
+}
+
+
+CFDictionaryRef
+SCUserPreferencesCopyInterfaceConfiguration(SCUserPreferencesRef       userPreferences,
+                                           SCNetworkInterfaceRef       interface)
+{
+       CFStringRef                     defaultType;
+       CFDictionaryRef                 entity          = NULL;
+       Boolean                         ok;
+       SCUserPreferencesPrivateRef     userPrivate     = (SCUserPreferencesPrivateRef)userPreferences;
+
+       if (!isA_SCUserPreferences(userPreferences)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return NULL;
+       }
+
+       if (!isA_SCNetworkInterface(interface)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return NULL;
+       }
+
+       // get InterfaceType
+       defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface);
+       if (defaultType == NULL) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return NULL;
+       }
+
+       // find SCUserPreferences and copy interface entity
+       ok = processPreferences(userPrivate->serviceID,
+                               copyInterfaceConfigurationCallout,
+                               (void *)userPrivate->prefsID,
+                               (void *)defaultType,
+                               (void *)&entity);
+       if (!ok) {
+               if (entity != NULL) {
+                       CFRelease(entity);
+                       entity = NULL;
+               }
+       }
+
+       return entity;
+}
+
+
+static CFDictionaryRef
+setInterfaceConfigurationCallout(CFStringRef           serviceID,
+                                 CFDictionaryRef       current,
+                                 void                  *context1,
+                                 void                  *context2,
+                                 void                  *context3)
+{
+       CFStringRef             interfaceType   = (CFStringRef)context2;
+       CFStringRef             matchID         = (CFStringRef)context1;
+       CFMutableDictionaryRef  newDict;
+       CFDictionaryRef         newOptions      = (CFDictionaryRef)context3;
+
+       if (current == NULL) {
+               // we have nothing to "add"
+               return NULL;
+       }
+
+       newDict = CFDictionaryCreateMutableCopy(NULL, 0, current);
+
+       if (isMatchingPrefsID(current, matchID)) {
+               if (newOptions != NULL) {
+                       CFDictionarySetValue(newDict, interfaceType, newOptions);
+
+                       // for backwards compatibility, we want to ensure that
+                       // the name is set in both the top level and in the PPP
+                       // entity.
+                       if (CFEqual(interfaceType, kSCEntNetPPP)) {
+                               CFStringRef     name;
+
+                               name = CFDictionaryGetValue(newOptions, kSCPropUserDefinedName);
+                               if (name != NULL) {
+                                       // if name was passed in newOptions, push up
+                                       CFDictionarySetValue(newDict, kSCPropUserDefinedName, name);
+                               } else {
+                                       name = CFDictionaryGetValue(newDict, kSCPropUserDefinedName);
+                                       if (name != NULL) {
+                                               CFMutableDictionaryRef  newPPPEntity;
+
+                                               // if name in parent, push into entity
+                                               newPPPEntity = CFDictionaryCreateMutableCopy(NULL, 0, newOptions);
+                                               CFDictionarySetValue(newPPPEntity, kSCPropUserDefinedName, name);
+                                               CFDictionarySetValue(newDict, interfaceType, newPPPEntity);
+                                               CFRelease(newPPPEntity);
+                                       }
+                               }
+                       }
+               } else {
+                       CFDictionaryRemoveValue(newDict, interfaceType);
+               }
+       }
+
+       return newDict;
+}
+
+
+Boolean
+SCUserPreferencesSetInterfaceConfiguration(SCUserPreferencesRef                userPreferences,
+                                          SCNetworkInterfaceRef        interface,
+                                          CFDictionaryRef              newOptions)
+{
+       CFStringRef                     defaultType;
+       Boolean                         ok;
+       SCUserPreferencesPrivateRef     userPrivate     = (SCUserPreferencesPrivateRef)userPreferences;
+
+       if (!isA_SCUserPreferences(userPreferences)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
+       if (!isA_SCNetworkInterface(interface)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
+       // get InterfaceType
+       defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface);
+       if (defaultType == NULL) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
+       // set new interface entity for SCUserPreferences
+       ok = processPreferences(userPrivate->serviceID,
+                               setInterfaceConfigurationCallout,
+                               (void *)userPrivate->prefsID,
+                               (void *)defaultType,
+                               (void *)newOptions);
+
+       return ok;
+}
+
+
+CFDictionaryRef
+SCUserPreferencesCopyExtendedInterfaceConfiguration(SCUserPreferencesRef       userPreferences,
+                                                   SCNetworkInterfaceRef       interface,
+                                                   CFStringRef                 extendedType)
+{
+       CFDictionaryRef                 entity          = NULL;
+       Boolean                         ok;
+       SCUserPreferencesPrivateRef     userPrivate     = (SCUserPreferencesPrivateRef)userPreferences;
+
+       if (!isA_SCUserPreferences(userPreferences)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return NULL;
+       }
+
+       if (!isA_SCNetworkInterface(interface)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return NULL;
+       }
+
+       if (!__SCNetworkInterfaceIsValidExtendedConfigurationType(interface, extendedType, FALSE)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return NULL;
+       }
+
+       // find SCUserPreferences and copy interface entity
+       ok = processPreferences(userPrivate->serviceID,
+                               copyInterfaceConfigurationCallout,
+                               (void *)userPrivate->prefsID,
+                               (void *)extendedType,
+                               (void *)&entity);
+       if (!ok) {
+               if (entity != NULL) {
+                       CFRelease(entity);
+                       entity = NULL;
+               }
+       }
+
+       return entity;
+}
+
+
+Boolean
+SCUserPreferencesSetExtendedInterfaceConfiguration(SCUserPreferencesRef                userPreferences,
+                                                  SCNetworkInterfaceRef        interface,
+                                                  CFStringRef                  extendedType,
+                                                  CFDictionaryRef              newOptions)
+{
+       Boolean                         ok;
+       SCUserPreferencesPrivateRef     userPrivate     = (SCUserPreferencesPrivateRef)userPreferences;
+
+       if (!isA_SCUserPreferences(userPreferences)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
+       if (!isA_SCNetworkInterface(interface)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
+       if (!__SCNetworkInterfaceIsValidExtendedConfigurationType(interface, extendedType, FALSE)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
+       // set new interface entity for SCUserPreferences
+       ok = processPreferences(userPrivate->serviceID,
+                               setInterfaceConfigurationCallout,
+                               (void *)userPrivate->prefsID,
+                               (void *)extendedType,
+                               (void *)newOptions);
+
+       return ok;
+}
+
+
+#pragma mark -
+#pragma mark SCNetworkConnection + SCUserPreferences SPIs
+
+
+static CFDictionaryRef
+copyAllCallout(CFStringRef     serviceID,
+              CFDictionaryRef  current,
+              void             *context1,
+              void             *context2,
+              void             *context3)
+{
+       CFMutableArrayRef               *prefs          = (CFMutableArrayRef *)context3;
+       CFStringRef                     prefsID;
+       SCUserPreferencesPrivateRef     userPrivate;
+
+       if (current == NULL) {
+               // we have nothing to "add"
+               return NULL;
+       }
+
+       prefsID = CFDictionaryGetValue(current, USER_PREFERENCES_ID);
+       if (!isA_CFString(prefsID)) {
+               // if no unique ID
+               goto done;
+       }
+
+       userPrivate = __SCUserPreferencesCreatePrivate(NULL, serviceID, prefsID);
+       if (userPrivate != NULL) {
+               if (*prefs == NULL) {
+                       *prefs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+               }
+               CFArrayAppendValue(*prefs, (SCUserPreferencesRef)userPrivate);
+               CFRelease(userPrivate);
+       }
+
+    done :
+
+       return CFRetain(current);
+}
+
+
+CFArrayRef /* of SCUserPreferencesRef's */
+SCNetworkConnectionCopyAllUserPreferences(SCNetworkConnectionRef connection)
+{
+       Boolean                 ok;
+       CFMutableArrayRef       prefs           = NULL;
+       CFStringRef             serviceID;
+
+       // get serviceID
+       serviceID = SCNetworkConnectionCopyServiceID(connection);
+
+       // collect SCUserPreferences
+       ok = processPreferences(serviceID,
+                               copyAllCallout,
+                               NULL,
+                               NULL,
+                               (void *)&prefs);
+       if (!ok) {
+               if (prefs != NULL) {
+                       CFRelease(prefs);
+                       prefs = NULL;
+               }
+       }
+
+       CFRelease(serviceID);
+       return prefs;
+}
+
+
+static CFDictionaryRef
+copyCurrentCallout(CFStringRef         serviceID,
+                  CFDictionaryRef      current,
+                  void                 *context1,
+                  void                 *context2,
+                  void                 *context3)
+{
+       CFBooleanRef                    isDefault;
+       CFStringRef                     prefsID;
+       SCUserPreferencesPrivateRef     *userPrivate    = (SCUserPreferencesPrivateRef *)context3;
+
+       if (current == NULL) {
+               // we have nothing to "add"
+               return NULL;
+       }
+
+       prefsID = CFDictionaryGetValue(current, USER_PREFERENCES_ID);
+       if (!isA_CFString(prefsID)) {
+               // if no unique ID
+               goto done;
+       }
+
+       isDefault = CFDictionaryGetValue(current, USER_PREFERENCES_DEFAULT);
+       if (!isA_CFBoolean(isDefault) || !CFBooleanGetValue(isDefault)) {
+               // if not the default configuration
+               goto done;
+       }
+
+       *userPrivate = __SCUserPreferencesCreatePrivate(NULL, serviceID, prefsID);
+
+    done :
+
+       return CFRetain(current);
+}
+
+
+SCUserPreferencesRef
+SCNetworkConnectionCopyCurrentUserPreferences(SCNetworkConnectionRef connection)
+{
+       SCUserPreferencesRef    current         = NULL;
+       Boolean                 ok;
+       CFStringRef             serviceID;
+
+       // get serviceID
+       serviceID = SCNetworkConnectionCopyServiceID(connection);
+
+       // collect SCUserPreferences
+       ok = processPreferences(serviceID,
+                               copyCurrentCallout,
+                               NULL,
+                               NULL,
+                               (void *)&current);
+       if (!ok) {
+               if (current != NULL) {
+                       CFRelease(current);
+                       current = NULL;
+               }
+       }
+
+       CFRelease(serviceID);
+       return current;
+}
+
+
+static CFDictionaryRef
+createCallout(CFStringRef      serviceID,
+             CFDictionaryRef   current,
+             void              *context1,
+             void              *context2,
+             void              *context3)
+{
+       CFMutableDictionaryRef          newDict;
+       CFStringRef                     newPrefsID      = (CFStringRef)context1;
+
+       if (current != NULL) {
+               // don't change existing entries
+               return CFRetain(current);
+       }
+
+       newDict = CFDictionaryCreateMutable(NULL,
+                                           0,
+                                           &kCFTypeDictionaryKeyCallBacks,
+                                           &kCFTypeDictionaryValueCallBacks);
+       CFDictionarySetValue(newDict, USER_PREFERENCES_ID, newPrefsID);
+       return newDict;
+}
+
+
+SCUserPreferencesRef
+SCNetworkConnectionCreateUserPreferences(SCNetworkConnectionRef connection)
+{
+       CFStringRef                     newPrefsID;
+       CFStringRef                     serviceID;
+       SCUserPreferencesPrivateRef     userPrivate;
+       CFUUIDRef                       uuid;
+
+       // get serviceID
+       serviceID = SCNetworkConnectionCopyServiceID(connection);
+
+       // allocate a new user preferences ID
+       uuid       = CFUUIDCreate(NULL);
+       newPrefsID = CFUUIDCreateString(NULL, uuid);
+       CFRelease(uuid);
+
+       userPrivate = __SCUserPreferencesCreatePrivate(NULL, serviceID, newPrefsID);
+       if (userPrivate != NULL) {
+               (void) processPreferences(serviceID,
+                                         createCallout,
+                                         (void *)newPrefsID,
+                                         NULL,
+                                         NULL);
+       }
+
+       CFRelease(newPrefsID);
+       CFRelease(serviceID);
+       return (SCUserPreferencesRef)userPrivate;
+}
+
+
+#ifdef NOTNOW
+Boolean
+SCNetworkConnectionSelectService(CFDictionaryRef       selectionOptions,
+                                SCNetworkServiceRef    *service,
+                                SCUserPreferencesRef   *userPreferences)
+{
+       return FALSE;
+}
+#endif // NOTNOW
+
+
+static void
+update_PPP_entity(SCUserPreferencesRef userPreferences, CFDictionaryRef *userOptions)
+{
+       CFStringRef     encryption;
+       CFDictionaryRef entity;
+       CFStringRef     keychainID;
+
+       entity = CFDictionaryGetValue(*userOptions, kSCEntNetPPP);
+       if (!isA_CFDictionary(entity)) {
+               return;
+       }
+
+       encryption = CFDictionaryGetValue(entity, kSCPropNetPPPAuthPasswordEncryption);
+       if (encryption == NULL) {
+               // provide default encryption method
+               encryption = kSCValNetPPPAuthPasswordEncryptionKeychain;
+       }
+
+       if (!isA_CFString(encryption) ||
+           !CFEqual(encryption, kSCValNetPPPAuthPasswordEncryptionKeychain)) {
+               return;
+       }
+
+       keychainID = CFDictionaryGetValue(entity, kSCPropNetPPPAuthPassword);
+       if (isA_CFString(keychainID)) {
+               // if password is keychain ID
+       } else if (isA_CFData(keychainID) &&
+                  ((CFDataGetLength((CFDataRef)keychainID) % sizeof(UniChar)) == 0)) {
+               // if inline password
+               return;
+       } else {
+               keychainID = SCUserPreferencesGetUniqueID(userPreferences);
+       }
+
+       if (_SCSecKeychainPasswordItemExists(NULL, keychainID)) {
+               CFMutableDictionaryRef  new_entity;
+               CFMutableDictionaryRef  new_options;
+
+               // access PPP password from system keychain
+               new_entity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
+
+               CFDictionarySetValue(new_entity,
+                                    kSCPropNetPPPAuthPassword,
+                                    keychainID);
+               CFDictionarySetValue(new_entity,
+                                    kSCPropNetPPPAuthPasswordEncryption,
+                                    kSCValNetPPPAuthPasswordEncryptionKeychain);
+
+               new_options = CFDictionaryCreateMutableCopy(NULL, 0, *userOptions);
+               CFDictionarySetValue(new_options, kSCEntNetPPP, new_entity);
+               CFRelease(new_entity);
+
+               CFRelease(*userOptions);
+               *userOptions = new_options;
+       }
+
+       return;
+}
+
+
+static void
+update_IPSec_entity(SCUserPreferencesRef userPreferences, CFDictionaryRef *userOptions)
+{
+       CFStringRef     encryption;
+       CFDictionaryRef entity;
+       SecKeychainRef  keychain        = NULL;
+       CFStringRef     keychainID;
+       CFStringRef     method;
+       CFDataRef       sharedSecret;
+
+       entity = CFDictionaryGetValue(*userOptions, kSCEntNetIPSec);
+       if (!isA_CFDictionary(entity)) {
+               return;
+       }
+
+       method = CFDictionaryGetValue(entity, kSCPropNetIPSecAuthenticationMethod);
+       if (!isA_CFString(method) ||
+           !CFEqual(method, kSCValNetIPSecAuthenticationMethodSharedSecret)) {
+               return;
+       }
+
+       encryption = CFDictionaryGetValue(entity, kSCPropNetIPSecSharedSecretEncryption);
+       if (encryption == NULL) {
+               // provide default encryption method
+               encryption = kSCValNetIPSecSharedSecretEncryptionKeychain;
+       }
+
+       if (!isA_CFString(encryption) ||
+           !CFEqual(encryption, kSCValNetIPSecSharedSecretEncryptionKeychain)) {
+               return;
+       }
+
+       keychainID = CFDictionaryGetValue(entity, kSCPropNetIPSecSharedSecret);
+       if (isA_CFString(keychainID)) {
+               // if shared secret is keychain ID
+               CFRetain(keychainID);
+       } else if (isA_CFData(keychainID) &&
+                  ((CFDataGetLength((CFDataRef)keychainID) % sizeof(UniChar)) == 0)) {
+               // if inline shared secret
+               return;
+       } else {
+               CFStringRef     unique_id;
+
+               unique_id = SCUserPreferencesGetUniqueID(userPreferences);
+               keychainID = (CFStringRef)CFStringCreateMutableCopy(NULL, 0, unique_id);
+               CFStringAppend((CFMutableStringRef)keychainID, CFSTR(".SS"));
+       }
+
+       sharedSecret = _SCSecKeychainPasswordItemCopy(NULL, keychainID);
+       if (sharedSecret != NULL) {
+               CFMutableDictionaryRef  new_entity;
+               CFMutableDictionaryRef  new_options;
+               CFStringRef             password;
+
+               // pass SharedSecret from user keychain
+               new_entity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
+
+               password = CFStringCreateWithBytes(NULL,
+                                                  CFDataGetBytePtr(sharedSecret),
+                                                  CFDataGetLength(sharedSecret),
+                                                  kCFStringEncodingUTF8,
+                                                  FALSE);
+               CFRelease(sharedSecret);
+               CFDictionarySetValue(new_entity,
+                                    kSCPropNetIPSecSharedSecret,
+                                    password);
+               CFRelease(password);
+               CFDictionaryRemoveValue(new_entity,
+                                       kSCPropNetIPSecSharedSecretEncryption);
+
+               new_options = CFDictionaryCreateMutableCopy(NULL, 0, *userOptions);
+               CFDictionarySetValue(new_options, kSCEntNetIPSec, new_entity);
+               CFRelease(new_entity);
+
+               CFRelease(*userOptions);
+               *userOptions = new_options;
+               goto done;
+       }
+
+       keychain = _SCSecKeychainCopySystemKeychain();
+       if (keychain == NULL) {
+               goto done;
+       }
+
+       if (_SCSecKeychainPasswordItemExists(keychain, keychainID)) {
+               CFMutableDictionaryRef  new_entity;
+               CFMutableDictionaryRef  new_options;
+
+               // access SharedSecret from system keychain
+               new_entity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
+
+               CFDictionarySetValue(new_entity,
+                                    kSCPropNetIPSecSharedSecret,
+                                    keychainID);
+               CFDictionarySetValue(new_entity,
+                                    kSCPropNetIPSecSharedSecretEncryption,
+                                    kSCValNetIPSecSharedSecretEncryptionKeychain);
+
+               new_options = CFDictionaryCreateMutableCopy(NULL, 0, *userOptions);
+               CFDictionarySetValue(new_options, kSCEntNetIPSec, new_entity);
+               CFRelease(new_entity);
+
+               CFRelease(*userOptions);
+               *userOptions = new_options;
+       }
+
+    done :
+
+       if (keychain != NULL) CFRelease(keychain);
+       CFRelease(keychainID);
+       return;
+}
+
+
+static CFDictionaryRef
+copyOptionsCallout(CFStringRef         serviceID,
+                  CFDictionaryRef      current,
+                  void                 *context1,
+                  void                 *context2,
+                  void                 *context3)
+{
+       CFStringRef             matchID         = (CFStringRef)context1;
+       CFMutableDictionaryRef  *userOptions    = (CFMutableDictionaryRef *)context3;
+
+       if (current == NULL) {
+               // we have nothing to "add"
+               return NULL;
+       }
+
+       if (isMatchingPrefsID(current, matchID)) {
+               // if we match, return options dictionary
+               if (*userOptions != NULL) CFRelease(*userOptions);
+               *userOptions = CFDictionaryCreateMutableCopy(NULL, 0, current);
+               CFDictionaryRemoveValue(*userOptions, USER_PREFERENCES_ID);
+               CFDictionaryRemoveValue(*userOptions, USER_PREFERENCES_DEFAULT);
+       }
+
+       return CFRetain(current);
+}
+
+
+Boolean
+SCNetworkConnectionStartWithUserPreferences(SCNetworkConnectionRef     connection,
+                                           SCUserPreferencesRef        userPreferences,
+                                           Boolean                     linger)
+{
+       Boolean                         ok;
+       CFDictionaryRef                 userOptions     = NULL;
+       SCUserPreferencesPrivateRef     userPrivate     = (SCUserPreferencesPrivateRef)userPreferences;
+
+       if (!isA_SCUserPreferences(userPreferences)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
+       (void) processPreferences(userPrivate->serviceID,
+                                 copyOptionsCallout,
+                                 (void *)userPrivate->prefsID,
+                                 NULL,
+                                 &userOptions);
+
+       /*
+        * For some legacy preferences, some of the user options
+        * were missing yet handled by the APIs.  Make sure that
+        * everything still works!
+        */
+       if (userOptions != NULL) {
+               update_PPP_entity  (userPreferences, &userOptions);
+               update_IPSec_entity(userPreferences, &userOptions);
+       }
+
+       ok = SCNetworkConnectionStart(connection, userOptions, linger);
+
+       if (userOptions != NULL) {
+               CFRelease(userOptions);
+       }
+
+       return ok;
+}
+
+
+#pragma mark -
+#pragma mark SCUserPreferences + SCNetworkInterface Password SPIs
+
+
+static CFStringRef
+getUserPasswordID(CFDictionaryRef config, SCUserPreferencesRef userPreferences)
+{
+       CFStringRef     unique_id       = NULL;
+
+       if (config != NULL) {
+               CFStringRef     encryption;
+
+               encryption = CFDictionaryGetValue(config, kSCPropNetPPPAuthPasswordEncryption);
+               if (isA_CFString(encryption) &&
+                   CFEqual(encryption, kSCValNetPPPAuthPasswordEncryptionKeychain)) {
+                       unique_id = CFDictionaryGetValue(config, kSCPropNetPPPAuthPassword);
+               }
+       }
+       if (unique_id == NULL) {
+               unique_id = SCUserPreferencesGetUniqueID(userPreferences);
+       }
+
+       return unique_id;
+}
+
+
+static CFStringRef
+copyUserSharedSecretID(CFDictionaryRef config, SCUserPreferencesRef userPreferences)
+{
+       CFMutableStringRef      sharedSecret    = NULL;
+
+       if (config != NULL) {
+               CFStringRef     encryption;
+
+               encryption = CFDictionaryGetValue(config, kSCPropNetIPSecSharedSecretEncryption);
+               if (isA_CFString(encryption) &&
+                   CFEqual(encryption, kSCValNetIPSecSharedSecretEncryptionKeychain)) {
+                       sharedSecret = (CFMutableStringRef)CFDictionaryGetValue(config, kSCPropNetIPSecSharedSecret);
+                       if (sharedSecret != NULL) {
+                               CFRetain(sharedSecret);
+                       }
+               }
+       }
+
+       if (sharedSecret == NULL) {
+               CFStringRef     unique_id;
+
+               unique_id = getUserPasswordID(config, userPreferences);
+               sharedSecret = CFStringCreateMutableCopy(NULL, 0, unique_id);
+               CFStringAppend(sharedSecret, CFSTR(".SS"));
+       }
+
+       return sharedSecret;
+}
+
+
+static Boolean
+checkUserPreferencesPassword(SCUserPreferencesRef              userPreferences,
+                            SCNetworkInterfaceRef              interface,
+                            SCNetworkInterfacePasswordType     passwordType)
+{
+       if (!isA_SCUserPreferences(userPreferences)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
+       if (!isA_SCNetworkInterface(interface)) {
+               _SCErrorSet(kSCStatusInvalidArgument);
+               return FALSE;
+       }
+
+       switch (passwordType) {
+               case kSCNetworkInterfacePasswordTypePPP : {
+                       CFStringRef     interfaceType;
+
+                       interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
+                       if (!CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
+                               _SCErrorSet(kSCStatusInvalidArgument);
+                               return FALSE;
+                       }
+                       break;
+               }
+
+               case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : {
+                       CFStringRef             interfaceType;
+
+                       interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
+                       if (!CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
+                               _SCErrorSet(kSCStatusInvalidArgument);
+                               return FALSE;
+                       }
+
+                       interface = SCNetworkInterfaceGetInterface(interface);
+                       if (interface == NULL) {
+                               _SCErrorSet(kSCStatusInvalidArgument);
+                               return FALSE;
+                       }
+
+                       interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
+                       if (!CFEqual(interfaceType, kSCNetworkInterfaceTypeL2TP)) {
+                               _SCErrorSet(kSCStatusInvalidArgument);
+                               return FALSE;
+                       }
+                       break;
+               }
+
+               case kSCNetworkInterfacePasswordTypeEAPOL : {
+                       _SCErrorSet(kSCStatusInvalidArgument);
+                       return FALSE;
+               }
+
+               default :
+                       break;
+       }
+
+       return TRUE;
+}
+
+
+Boolean
+SCUserPreferencesCheckInterfacePassword(SCUserPreferencesRef           userPreferences,
+                                       SCNetworkInterfaceRef           interface,
+                                       SCNetworkInterfacePasswordType  passwordType)
+{
+       Boolean         exists  = FALSE;
+
+       if (!checkUserPreferencesPassword(userPreferences, interface, passwordType)) {
+               return FALSE;
+       }
+
+       switch (passwordType) {
+               case kSCNetworkInterfacePasswordTypePPP : {
+                       CFDictionaryRef config;
+                       CFStringRef     unique_id;
+
+                       // get configuration
+                       config = SCUserPreferencesCopyInterfaceConfiguration(userPreferences, interface);
+
+                       // get userPreferences ID
+                       unique_id = getUserPasswordID(config, userPreferences);
+
+                       // check
+                       exists = __extract_password(NULL,
+                                                   config,
+                                                   kSCPropNetPPPAuthPassword,
+                                                   kSCPropNetPPPAuthPasswordEncryption,
+                                                   kSCValNetPPPAuthPasswordEncryptionKeychain,
+                                                   unique_id,
+                                                   NULL);
+
+                       if (config != NULL)     CFRelease(config);
+                       break;
+               }
+
+               case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : {
+                       CFDictionaryRef config;
+                       CFStringRef     shared_id;
+
+                       // get configuration
+                       config = SCUserPreferencesCopyExtendedInterfaceConfiguration(userPreferences,
+                                                                                    interface,
+                                                                                    kSCEntNetIPSec);
+
+                       // get sharedSecret ID
+                       shared_id = copyUserSharedSecretID(config, userPreferences);
+
+                       // check
+                       exists = __extract_password(NULL,
+                                                   config,
+                                                   kSCPropNetIPSecSharedSecret,
+                                                   kSCPropNetIPSecSharedSecretEncryption,
+                                                   kSCValNetIPSecSharedSecretEncryptionKeychain,
+                                                   shared_id,
+                                                   NULL);
+
+                       if (config != NULL)     CFRelease(config);
+                               CFRelease(shared_id);
+                       break;
+               }
+
+               default :
+                       _SCErrorSet(kSCStatusInvalidArgument);
+                       return FALSE;
+       }
+
+       return exists;
+}
+
+
+CFDataRef
+SCUserPreferencesCopyInterfacePassword(SCUserPreferencesRef            userPreferences,
+                                      SCNetworkInterfaceRef            interface,
+                                      SCNetworkInterfacePasswordType   passwordType)
+{
+       CFDataRef       password        = NULL;
+
+       if (!checkUserPreferencesPassword(userPreferences, interface, passwordType)) {
+               return FALSE;
+       }
+
+       switch (passwordType) {
+               case kSCNetworkInterfacePasswordTypePPP : {
+                       CFDictionaryRef config;
+                       CFStringRef     unique_id;
+
+                       // get configuration
+                       config = SCUserPreferencesCopyInterfaceConfiguration(userPreferences, interface);
+
+                       // get userPreferences ID
+                       unique_id = getUserPasswordID(config, userPreferences);
+
+                       // extract
+                       (void) __extract_password(NULL,
+                                                 config,
+                                                 kSCPropNetPPPAuthPassword,
+                                                 kSCPropNetPPPAuthPasswordEncryption,
+                                                 kSCValNetPPPAuthPasswordEncryptionKeychain,
+                                                 unique_id,
+                                                 &password);
+
+                       if (config != NULL)     CFRelease(config);
+                       break;
+               }
+
+               case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : {
+                       CFDictionaryRef config;
+                       CFStringRef     shared_id;
+
+                       // get configuration
+                       config = SCUserPreferencesCopyExtendedInterfaceConfiguration(userPreferences,
+                                                                                    interface,
+                                                                                    kSCEntNetIPSec);
+
+                       // get sharedSecret ID
+                       shared_id = copyUserSharedSecretID(config, userPreferences);
+
+                       // extract
+                       (void) __extract_password(NULL,
+                                                 config,
+                                                 kSCPropNetIPSecSharedSecret,
+                                                 kSCPropNetIPSecSharedSecretEncryption,
+                                                 kSCValNetIPSecSharedSecretEncryptionKeychain,
+                                                 shared_id,
+                                                 &password);
+
+                       if (config != NULL)     CFRelease(config);
+                               CFRelease(shared_id);
+                       break;
+               }
+
+               default :
+                       _SCErrorSet(kSCStatusInvalidArgument);
+                       return NULL;
+       }
+
+       return password;
+}
+
+
+Boolean
+SCUserPreferencesRemoveInterfacePassword(SCUserPreferencesRef          userPreferences,
+                                        SCNetworkInterfaceRef          interface,
+                                        SCNetworkInterfacePasswordType passwordType)
+{
+       Boolean         ok      = FALSE;
+
+       if (!checkUserPreferencesPassword(userPreferences, interface, passwordType)) {
+               return FALSE;
+       }
+
+       switch (passwordType) {
+               case kSCNetworkInterfacePasswordTypePPP : {
+                       CFDictionaryRef config;
+                       CFStringRef     unique_id;
+
+                       // get configuration
+                       config = SCUserPreferencesCopyInterfaceConfiguration(userPreferences, interface);
+
+                       // get userPreferences ID
+                       unique_id = getUserPasswordID(config, userPreferences);
+
+                       // remove password
+                       ok = _SCSecKeychainPasswordItemRemove(NULL, unique_id);
+                       if (ok) {
+                               CFDictionaryRef         config;
+                               CFMutableDictionaryRef  newConfig;
+
+                               config = SCUserPreferencesCopyInterfaceConfiguration(userPreferences, interface);
+                               if (config != NULL) {
+                                       newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
+                                       CFDictionaryRemoveValue(newConfig, kSCPropNetPPPAuthPassword);
+                                       CFDictionaryRemoveValue(newConfig, kSCPropNetPPPAuthPasswordEncryption);
+                                       ok = SCUserPreferencesSetInterfaceConfiguration(userPreferences, interface, newConfig);
+                                       CFRelease(newConfig);
+                               }
+                       }
+                       break;
+               }
+
+               case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : {
+                       CFDictionaryRef config;
+                       CFStringRef     shared_id;
+
+                       // get configuration
+                       config = SCUserPreferencesCopyExtendedInterfaceConfiguration(userPreferences,
+                                                                                    interface,
+                                                                                    kSCEntNetIPSec);
+
+                       // get sharedSecret ID
+                       shared_id = copyUserSharedSecretID(config, userPreferences);
+
+                       // remove password
+                       ok = _SCSecKeychainPasswordItemRemove(NULL, shared_id);
+                       if (ok) {
+                               CFMutableDictionaryRef  newConfig;
+
+                               if (config != NULL) {
+                                       newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
+                                       CFDictionaryRemoveValue(newConfig, kSCPropNetIPSecSharedSecret);
+                                       CFDictionaryRemoveValue(newConfig, kSCPropNetIPSecSharedSecretEncryption);
+                                       ok = SCUserPreferencesSetExtendedInterfaceConfiguration(userPreferences,
+                                                                                               interface,
+                                                                                               kSCEntNetIPSec,
+                                                                                               newConfig);
+                                       CFRelease(newConfig);
+                               }
+                       }
+
+                       if (config != NULL)     CFRelease(config);
+                       CFRelease(shared_id);
+                       break;
+               }
+
+               default :
+                       _SCErrorSet(kSCStatusInvalidArgument);
+                       return FALSE;
+       }
+
+       return ok;
+}
+
+
+Boolean
+SCUserPreferencesSetInterfacePassword(SCUserPreferencesRef             userPreferences,
+                                     SCNetworkInterfaceRef             interface,
+                                     SCNetworkInterfacePasswordType    passwordType,
+                                     CFDataRef                         password,
+                                     CFDictionaryRef                   options)
+{
+       CFStringRef     account         = NULL;
+       CFBundleRef     bundle;
+       CFDictionaryRef config;
+       CFStringRef     description     = NULL;
+       CFStringRef     label           = NULL;
+       Boolean         ok      = FALSE;
+
+       if (!checkUserPreferencesPassword(userPreferences, interface, passwordType)) {
+               return FALSE;
+       }
+
+       bundle = _SC_CFBundleGet();
+
+       switch (passwordType) {
+               case kSCNetworkInterfacePasswordTypePPP : {
+                       CFStringRef     unique_id;
+
+                       // get configuration
+                       config = SCUserPreferencesCopyInterfaceConfiguration(userPreferences, interface);
+
+                       // get userPreferences ID
+                       unique_id = getUserPasswordID(config, userPreferences);
+
+                       // User prefs auth name --> keychain "Account"
+                       if (config != NULL) {
+                               account = CFDictionaryGetValue(config, kSCPropNetPPPAuthName);
+                       }
+
+                       // User prefs "name" --> keychain "Name"
+                       label = SCUserPreferencesCopyName(userPreferences);
+
+                       // "PPP Password" --> keychain "Kind"
+                       if (bundle != NULL) {
+                               description = CFBundleCopyLocalizedString(bundle,
+                                                                         CFSTR("KEYCHAIN_PPP_PASSWORD"),
+                                                                         CFSTR("PPP Password"),
+                                                                         NULL);
+                       }
+
+                       // store password
+                       ok = _SCSecKeychainPasswordItemSet(NULL,
+                                                          unique_id,
+                                                          (label != NULL)       ? label       : CFSTR("PPP"),
+                                                          (description != NULL) ? description : CFSTR("PPP Password"),
+                                                          account,
+                                                          password,
+                                                          options);
+                       if (ok) {
+                               CFMutableDictionaryRef  newConfig;
+
+                               if (config != NULL) {
+                                       newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
+                               } else {
+                                       newConfig = CFDictionaryCreateMutable(NULL,
+                                                                             0,
+                                                                             &kCFTypeDictionaryKeyCallBacks,
+                                                                             &kCFTypeDictionaryValueCallBacks);
+                               }
+                               CFDictionarySetValue(newConfig,
+                                                    kSCPropNetPPPAuthPassword,
+                                                    unique_id);
+                               CFDictionarySetValue(newConfig,
+                                                    kSCPropNetPPPAuthPasswordEncryption,
+                                                    kSCValNetPPPAuthPasswordEncryptionKeychain);
+                               ok = SCUserPreferencesSetInterfaceConfiguration(userPreferences, interface, newConfig);
+                               CFRelease(newConfig);
+                       }
+
+                       if (config      != NULL) CFRelease(config);
+                       if (description != NULL) CFRelease(description);
+                       if (label       != NULL) CFRelease(label);
+                       break;
+               }
+
+               case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : {
+                       CFStringRef     shared_id;
+
+                       // get configuration
+                       config = SCUserPreferencesCopyExtendedInterfaceConfiguration(userPreferences,
+                                                                                    interface,
+                                                                                    kSCEntNetIPSec);
+
+                       // get sharedSecret ID
+                       shared_id = copyUserSharedSecretID(config, userPreferences);
+
+                       // User prefs "name" --> keychain "Name"
+                       label = SCUserPreferencesCopyName(userPreferences);
+
+                       // "IPSec Shared Secret" --> keychain "Kind"
+                       if (bundle != NULL) {
+                               description = CFBundleCopyLocalizedString(bundle,
+                                                                         CFSTR("KEYCHAIN_IPSEC_SHARED_SECRET"),
+                                                                         CFSTR("IPSec Shared Secret"),
+                                                                         NULL);
+                       }
+
+                       // set password
+                       ok = _SCSecKeychainPasswordItemSet(NULL,
+                                                          shared_id,
+                                                          (label != NULL)       ? label       : CFSTR("PPP"),
+                                                          (description != NULL) ? description : CFSTR("IPSec Shared Secret"),
+                                                          NULL,
+                                                          password,
+                                                          options);
+                       if (ok) {
+                               CFMutableDictionaryRef  newConfig       = NULL;
+
+                               if (config != NULL) {
+                                       newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
+                               } else {
+                                       newConfig = CFDictionaryCreateMutable(NULL,
+                                                                             0,
+                                                                             &kCFTypeDictionaryKeyCallBacks,
+                                                                             &kCFTypeDictionaryValueCallBacks);
+                               }
+                               CFDictionarySetValue(newConfig,
+                                                    kSCPropNetIPSecSharedSecret,
+                                                    shared_id);
+                               CFDictionarySetValue(newConfig,
+                                                    kSCPropNetIPSecSharedSecretEncryption,
+                                                    kSCValNetIPSecSharedSecretEncryptionKeychain);
+                               ok = SCUserPreferencesSetExtendedInterfaceConfiguration(userPreferences,
+                                                                                       interface,
+                                                                                       kSCEntNetIPSec,
+                                                                                       newConfig);
+                               CFRelease(newConfig);
+                       }
+
+                       if (config      != NULL) CFRelease(config);
+                       if (description != NULL) CFRelease(description);
+                       if (label       != NULL) CFRelease(label);
+                       CFRelease(shared_id);
+                       break;
+               }
+
+               default :
+                       _SCErrorSet(kSCStatusInvalidArgument);
+                       return FALSE;
+       }
+
+       return ok;
+}