summaryrefslogtreecommitdiffstats
path: root/mDNSResponder/mDNSMacOSX/PreferencePane
diff options
context:
space:
mode:
Diffstat (limited to 'mDNSResponder/mDNSMacOSX/PreferencePane')
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/add_idle.tiffbin0 -> 728 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/add_pressed.tiffbin0 -> 688 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/failure.tiffbin0 -> 638 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/inprogress.tiffbin0 -> 644 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_disabled.tiffbin0 -> 698 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_idle.tiffbin0 -> 694 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_pressed.tiffbin0 -> 656 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/success.tiffbin0 -> 676 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPref.icnsbin0 -> 39193 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPref.tiffbin0 -> 2430 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationAuthority.c180
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationAuthority.h52
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationRights.h49
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.h170
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m1194
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib/classes.nib59
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib/info.nib18
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib/keyedobjects.nibbin0 -> 21082 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/InfoPlist.stringsbin0 -> 484 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/Info-PreferencePane.plist36
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/PrivilegedOperations.c230
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/PrivilegedOperations.h70
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/ddnswriteconfig.m442
-rwxr-xr-xmDNSResponder/mDNSMacOSX/PreferencePane/installtool94
24 files changed, 2594 insertions, 0 deletions
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/add_idle.tiff b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/add_idle.tiff
new file mode 100644
index 00000000..b78b0c2a
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/add_idle.tiff
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/add_pressed.tiff b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/add_pressed.tiff
new file mode 100644
index 00000000..b842e20c
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/add_pressed.tiff
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/failure.tiff b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/failure.tiff
new file mode 100644
index 00000000..89a10dfe
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/failure.tiff
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/inprogress.tiff b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/inprogress.tiff
new file mode 100644
index 00000000..340bb335
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/inprogress.tiff
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_disabled.tiff b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_disabled.tiff
new file mode 100644
index 00000000..70d3dd9c
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_disabled.tiff
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_idle.tiff b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_idle.tiff
new file mode 100644
index 00000000..dacc97c3
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_idle.tiff
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_pressed.tiff b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_pressed.tiff
new file mode 100644
index 00000000..de3f8779
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_pressed.tiff
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/success.tiff b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/success.tiff
new file mode 100644
index 00000000..21702a9a
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/success.tiff
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPref.icns b/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPref.icns
new file mode 100644
index 00000000..5ba4674e
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPref.icns
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPref.tiff b/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPref.tiff
new file mode 100644
index 00000000..55cb212c
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPref.tiff
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationAuthority.c b/mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationAuthority.c
new file mode 100644
index 00000000..a2ab5464
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationAuthority.c
@@ -0,0 +1,180 @@
+/*
+ File: ConfigurationAuthority.c
+
+ Abstract: Interface to system security framework that manages access
+ to protected resources like system configuration preferences.
+
+ Copyright: (c) Copyright 2005 Apple Computer, Inc. All rights reserved.
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
+ ("Apple") in consideration of your agreement to the following terms, and your
+ use, installation, modification or redistribution of this Apple software
+ constitutes acceptance of these terms. If you do not agree with these terms,
+ please do not use, install, modify or redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject
+ to these terms, Apple grants you a personal, non-exclusive license, under Apple's
+ copyrights in this original Apple software (the "Apple Software"), to use,
+ reproduce, modify and redistribute the Apple Software, with or without
+ modifications, in source and/or binary forms; provided that if you redistribute
+ the Apple Software in its entirety and without modifications, you must retain
+ this notice and the following text and disclaimers in all such redistributions of
+ the Apple Software. Neither the name, trademarks, service marks or logos of
+ Apple Computer, Inc. may be used to endorse or promote products derived from the
+ Apple Software without specific prior written permission from Apple. Except as
+ expressly stated in this notice, no other rights or licenses, express or implied,
+ are granted by Apple herein, including but not limited to any patent rights that
+ may be infringed by your derivative works or by other works in which the Apple
+ Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ConfigurationAuthority.h"
+#include "ConfigurationRights.h"
+
+#include <AssertMacros.h>
+
+
+static AuthorizationRef gAuthRef = 0;
+
+static AuthorizationItem gAuthorizations[] = { { UPDATE_SC_RIGHT, 0, NULL, 0 },
+ { EDIT_SYS_KEYCHAIN_RIGHT, 0, NULL, 0 }};
+static AuthorizationRights gAuthSet = { sizeof gAuthorizations / sizeof gAuthorizations[0], gAuthorizations };
+
+static CFDictionaryRef CreateRightsDict( CFStringRef prompt)
+/* Create a CFDictionary decribing an auth right. See /etc/authorization for examples. */
+/* Specifies that the right requires admin authentication, which persists for 5 minutes. */
+{
+ CFMutableDictionaryRef dict = NULL, tmpDict;
+ CFMutableArrayRef mechanisms;
+ CFNumberRef timeout;
+ int val;
+
+ tmpDict = CFDictionaryCreateMutable( (CFAllocatorRef) NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ require( tmpDict != NULL, MakeDictFailed);
+
+ CFDictionaryAddValue(tmpDict, CFSTR("class"), CFSTR("user"));
+ CFDictionaryAddValue(tmpDict, CFSTR("comment"), prompt);
+ CFDictionaryAddValue(tmpDict, CFSTR("group"), CFSTR("admin"));
+
+ mechanisms = CFArrayCreateMutable((CFAllocatorRef) NULL, 1, &kCFTypeArrayCallBacks);
+ require( mechanisms != NULL, MakeArrayFailed);
+ CFArrayAppendValue( mechanisms, CFSTR("builtin:authenticate"));
+ CFDictionaryAddValue( tmpDict, CFSTR("mechanisms"), mechanisms);
+
+ val = 300; // seconds
+ timeout = CFNumberCreate((CFAllocatorRef) NULL, kCFNumberIntType, &val);
+ require( timeout != NULL, MakeIntFailed);
+ CFDictionaryAddValue( tmpDict, CFSTR("timeout"), timeout);
+ CFDictionaryAddValue( tmpDict, CFSTR("shared"), kCFBooleanTrue);
+
+ dict = tmpDict;
+ tmpDict = NULL;
+
+ CFRelease( timeout);
+MakeIntFailed:
+ CFRelease( mechanisms);
+MakeArrayFailed:
+ if ( tmpDict)
+ CFRelease( tmpDict);
+MakeDictFailed:
+ return dict;
+}
+
+OSStatus InitConfigAuthority(void)
+/* Initialize the authorization record-keeping */
+{
+ OSStatus err;
+ CFDictionaryRef dict;
+ CFStringRef rightInfo;
+
+ err = AuthorizationCreate((AuthorizationRights*) NULL, (AuthorizationEnvironment*) NULL,
+ (AuthorizationFlags) 0, &gAuthRef);
+ require_noerr( err, NewAuthFailed);
+
+ err = AuthorizationRightGet( UPDATE_SC_RIGHT, (CFDictionaryRef*) NULL);
+ if (err == errAuthorizationDenied)
+ {
+ rightInfo = CFCopyLocalizedString(CFSTR("Authentication required to set Dynamic DNS preferences."),
+ CFSTR("Describes operation that requires user authorization"));
+ require_action( rightInfo != NULL, GetStrFailed, err=coreFoundationUnknownErr;);
+ dict = CreateRightsDict(rightInfo);
+ require_action( dict != NULL, GetStrFailed, err=coreFoundationUnknownErr;);
+
+ err = AuthorizationRightSet(gAuthRef, UPDATE_SC_RIGHT, dict, (CFStringRef) NULL,
+ (CFBundleRef) NULL, (CFStringRef) NULL);
+ CFRelease(rightInfo);
+ CFRelease(dict);
+ }
+ require_noerr( err, AuthSetFailed);
+
+ err = AuthorizationRightGet( EDIT_SYS_KEYCHAIN_RIGHT, (CFDictionaryRef*) NULL);
+ if (err == errAuthorizationDenied)
+ {
+ rightInfo = CFCopyLocalizedString( CFSTR("Authentication required to edit System Keychain."),
+ CFSTR("Describes operation that requires user authorization"));
+ require_action( rightInfo != NULL, GetStrFailed, err=coreFoundationUnknownErr;);
+ dict = CreateRightsDict( rightInfo);
+ require_action( dict != NULL, GetStrFailed, err=coreFoundationUnknownErr;);
+
+ err = AuthorizationRightSet(gAuthRef, EDIT_SYS_KEYCHAIN_RIGHT, dict, (CFStringRef) NULL,
+ (CFBundleRef) NULL, (CFStringRef) NULL);
+ CFRelease( rightInfo);
+ CFRelease( dict);
+ }
+ require_noerr( err, AuthSetFailed);
+
+AuthSetFailed:
+GetStrFailed:
+NewAuthFailed:
+ return err;
+}
+
+OSStatus AttemptAcquireAuthority( Boolean allowUI)
+/* Try to get permission for privileged ops, either implicitly or by asking the user for */
+/* authority to perform operations (if necessary) */
+{
+ AuthorizationFlags allowFlag = allowUI ? kAuthorizationFlagInteractionAllowed : 0;
+ OSStatus err;
+
+ err = AuthorizationCopyRights( gAuthRef, &gAuthSet, (AuthorizationEnvironment*) NULL,
+ kAuthorizationFlagExtendRights | kAuthorizationFlagPreAuthorize |
+ allowFlag,
+ (AuthorizationRights**) NULL);
+ return err;
+}
+
+OSStatus ReleaseAuthority(void)
+/* Discard authority to perform operations */
+{
+ (void) AuthorizationFree( gAuthRef, kAuthorizationFlagDefaults);
+ gAuthRef = 0;
+ return AuthorizationCreate( (AuthorizationRights*) NULL, (AuthorizationEnvironment*) NULL,
+ (AuthorizationFlags) 0, &gAuthRef);
+}
+
+Boolean CurrentlyAuthorized(void)
+{
+ OSStatus err = AttemptAcquireAuthority(true);
+ return err == noErr;
+}
+
+
+OSStatus ExternalizeAuthority(AuthorizationExternalForm *pAuth)
+/* Package up current authorizations for transfer to another process */
+{
+ return AuthorizationMakeExternalForm(gAuthRef, pAuth);
+}
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationAuthority.h b/mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationAuthority.h
new file mode 100644
index 00000000..49da93d0
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationAuthority.h
@@ -0,0 +1,52 @@
+/*
+ File: ConfigurationAuthority.h
+
+ Abstract: Interface to system security framework that manages access
+ to protected resources like system configuration preferences.
+
+ Copyright: (c) Copyright 2005 Apple Computer, Inc. All rights reserved.
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
+ ("Apple") in consideration of your agreement to the following terms, and your
+ use, installation, modification or redistribution of this Apple software
+ constitutes acceptance of these terms. If you do not agree with these terms,
+ please do not use, install, modify or redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject
+ to these terms, Apple grants you a personal, non-exclusive license, under Apple's
+ copyrights in this original Apple software (the "Apple Software"), to use,
+ reproduce, modify and redistribute the Apple Software, with or without
+ modifications, in source and/or binary forms; provided that if you redistribute
+ the Apple Software in its entirety and without modifications, you must retain
+ this notice and the following text and disclaimers in all such redistributions of
+ the Apple Software. Neither the name, trademarks, service marks or logos of
+ Apple Computer, Inc. may be used to endorse or promote products derived from the
+ Apple Software without specific prior written permission from Apple. Except as
+ expressly stated in this notice, no other rights or licenses, express or implied,
+ are granted by Apple herein, including but not limited to any patent rights that
+ may be infringed by your derivative works or by other works in which the Apple
+ Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <CoreServices/CoreServices.h>
+#include <Security/Security.h>
+
+OSStatus InitConfigAuthority(void);
+Boolean CurrentlyAuthorized(void);
+OSStatus AttemptAcquireAuthority(Boolean allowUI);
+OSStatus ReleaseAuthority(void);
+OSStatus ExternalizeAuthority(AuthorizationExternalForm *pAuth);
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationRights.h b/mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationRights.h
new file mode 100644
index 00000000..44379c67
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationRights.h
@@ -0,0 +1,49 @@
+/*
+ File: ConfigurationRights.h
+
+ Abstract: Defines the rights we need, namely, (i) the right to write to
+ the system configuration settings for Dynamic DNS and Wide-Area DNS-SD,
+ and (ii) the right to write to the system keychain to store Dynamic DNS
+ shared secrets used to perform authorized updates to DDNS servers.
+ Right now these are both actually the same right: "system.preferences"
+
+ Copyright: (c) Copyright 2005 Apple Computer, Inc. All rights reserved.
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
+ ("Apple") in consideration of your agreement to the following terms, and your
+ use, installation, modification or redistribution of this Apple software
+ constitutes acceptance of these terms. If you do not agree with these terms,
+ please do not use, install, modify or redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject
+ to these terms, Apple grants you a personal, non-exclusive license, under Apple's
+ copyrights in this original Apple software (the "Apple Software"), to use,
+ reproduce, modify and redistribute the Apple Software, with or without
+ modifications, in source and/or binary forms; provided that if you redistribute
+ the Apple Software in its entirety and without modifications, you must retain
+ this notice and the following text and disclaimers in all such redistributions of
+ the Apple Software. Neither the name, trademarks, service marks or logos of
+ Apple Computer, Inc. may be used to endorse or promote products derived from the
+ Apple Software without specific prior written permission from Apple. Except as
+ expressly stated in this notice, no other rights or licenses, express or implied,
+ are granted by Apple herein, including but not limited to any patent rights that
+ may be infringed by your derivative works or by other works in which the Apple
+ Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define UPDATE_SC_RIGHT "system.preferences"
+#define EDIT_SYS_KEYCHAIN_RIGHT "system.preferences"
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.h b/mDNSResponder/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.h
new file mode 100644
index 00000000..f0586591
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.h
@@ -0,0 +1,170 @@
+/*
+ File: DNSServiceDiscoveryPref.h
+
+ Abstract: System Preference Pane for Dynamic DNS and Wide-Area DNS Service Discovery
+
+ Copyright: (c) Copyright 2005 Apple Computer, Inc. All rights reserved.
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
+ ("Apple") in consideration of your agreement to the following terms, and your
+ use, installation, modification or redistribution of this Apple software
+ constitutes acceptance of these terms. If you do not agree with these terms,
+ please do not use, install, modify or redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject
+ to these terms, Apple grants you a personal, non-exclusive license, under Apple's
+ copyrights in this original Apple software (the "Apple Software"), to use,
+ reproduce, modify and redistribute the Apple Software, with or without
+ modifications, in source and/or binary forms; provided that if you redistribute
+ the Apple Software in its entirety and without modifications, you must retain
+ this notice and the following text and disclaimers in all such redistributions of
+ the Apple Software. Neither the name, trademarks, service marks or logos of
+ Apple Computer, Inc. may be used to endorse or promote products derived from the
+ Apple Software without specific prior written permission from Apple. Except as
+ expressly stated in this notice, no other rights or licenses, express or implied,
+ are granted by Apple herein, including but not limited to any patent rights that
+ may be infringed by your derivative works or by other works in which the Apple
+ Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <Cocoa/Cocoa.h>
+#import <PreferencePanes/PreferencePanes.h>
+#import <CoreFoundation/CoreFoundation.h>
+#import <SecurityInterface/SFAuthorizationView.h>
+#import <SystemConfiguration/SystemConfiguration.h>
+#import <dns_sd.h>
+
+typedef struct MyDNSServiceState {
+ DNSServiceRef service;
+ CFRunLoopSourceRef source;
+ CFSocketRef socket;
+} MyDNSServiceState;
+
+
+@interface DNSServiceDiscoveryPref : NSPreferencePane
+{
+ IBOutlet NSTextField *hostName;
+ IBOutlet NSTextField *sharedSecretName;
+ IBOutlet NSSecureTextField *sharedSecretValue;
+ IBOutlet NSComboBox *browseDomainsComboBox;
+ IBOutlet NSComboBox *regDomainsComboBox;
+ IBOutlet NSButton *wideAreaCheckBox;
+ IBOutlet NSButton *hostNameSharedSecretButton;
+ IBOutlet NSButton *registrationSharedSecretButton;
+ IBOutlet NSButton *applyButton;
+ IBOutlet NSButton *revertButton;
+ IBOutlet NSWindow *sharedSecretWindow;
+ IBOutlet NSWindow *addBrowseDomainWindow;
+ IBOutlet NSButton *addBrowseDomainButton;
+ IBOutlet NSButton *removeBrowseDomainButton;
+ IBOutlet NSButton *browseOKButton;
+ IBOutlet NSButton *browseCancelButton;
+ IBOutlet NSButton *secretOKButton;
+ IBOutlet NSButton *secretCancelButton;
+ IBOutlet NSImageView *statusImageView;
+ IBOutlet NSTabView *tabView;
+ IBOutlet NSTableView *browseDomainList;
+ IBOutlet SFAuthorizationView *comboAuthButton;
+
+ NSWindow *mainWindow;
+ NSString *currentHostName;
+ NSString *currentRegDomain;
+ NSArray *currentBrowseDomainsArray;
+ NSMutableArray *browseDomainsArray;
+ NSMutableArray *defaultBrowseDomainsArray;
+ NSString *defaultRegDomain;
+
+ NSString *hostNameSharedSecretName;
+ NSString *hostNameSharedSecretValue;
+ NSString *regSharedSecretName;
+ NSString *regSharedSecretValue;
+ BOOL currentWideAreaState;
+ BOOL prefsNeedUpdating;
+ BOOL toolInstalled;
+ BOOL browseDomainListEnabled;
+ BOOL justStartedEditing;
+ NSImage *successImage;
+ NSImage *inprogressImage;
+ NSImage *failureImage;
+
+ MyDNSServiceState regQuery;
+ MyDNSServiceState browseQuery;
+ NSMutableArray *browseDataSource;
+ NSMutableArray *registrationDataSource;
+}
+
+-(IBAction)applyClicked : (id)sender;
+-(IBAction)enableBrowseDomainClicked : (id)sender;
+-(IBAction)addBrowseDomainClicked : (id)sender;
+-(IBAction)removeBrowseDomainClicked : (id)sender;
+-(IBAction)revertClicked : (id)sender;
+-(IBAction)changeButtonPressed : (id)sender;
+-(IBAction)closeMyCustomSheet : (id)sender;
+-(IBAction)comboAction : (id)sender;
+-(IBAction)wideAreaCheckBoxChanged : (id)sender;
+
+
+-(NSMutableArray *)browseDataSource;
+-(NSMutableArray *)registrationDataSource;
+-(NSComboBox *)browseDomainsComboBox;
+-(NSComboBox *)regDomainsComboBox;
+-(NSString *)currentRegDomain;
+-(NSMutableArray *)defaultBrowseDomainsArray;
+-(NSArray *)currentBrowseDomainsArray;
+-(NSString *)currentHostName;
+-(NSString *)defaultRegDomain;
+-(void)setDefaultRegDomain : (NSString *)domain;
+
+
+
+-(void)enableApplyButton;
+-(void)disableApplyButton;
+-(void)applyCurrentState;
+-(void)setBrowseDomainsComboBox;
+-(void)setupInitialValues;
+-(void)startDomainBrowsing;
+-(void)toggleWideAreaBonjour : (BOOL)state;
+-(void)updateApplyButtonState;
+-(void)enableControls;
+-(void)disableControls;
+-(void)validateTextFields;
+-(void)readPreferences;
+-(void)savePreferences;
+-(void)restorePreferences;
+-(void)watchForPreferenceChanges;
+-(void)updateStatusImageView;
+
+
+-(NSString *)sharedSecretKeyName : (NSString * )domain;
+-(NSString *)domainForHostName : (NSString *)hostNameString;
+-(int)statusForHostName : (NSString * )domain;
+-(NSData *)dataForDomainArray : (NSArray *)domainArray;
+-(NSData *)dataForDomain : (NSString *)domainName isEnabled : (BOOL)enabled;
+-(NSData *)dataForSharedSecret : (NSString *)secret domain : (NSString *)domainName key : (NSString *)keyName;
+-(BOOL)domainAlreadyInList : (NSString *)domainString;
+-(NSString *)trimCharactersFromDomain : (NSString *)domain;
+
+
+// Delegate methods
+-(void)authorizationViewDidAuthorize : (SFAuthorizationView *)view;
+-(void)authorizationViewDidDeauthorize : (SFAuthorizationView *)view;
+-(void)mainViewDidLoad;
+-(int)numberOfItemsInComboBox : (NSComboBox *)aComboBox;
+-(id)comboBox : (NSComboBox *)aComboBox objectValueForItemAtIndex : (int)index;
+-(void)controlTextDidChange : (NSNotification *) notification;
+
+@end
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m b/mDNSResponder/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m
new file mode 100644
index 00000000..063bc724
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m
@@ -0,0 +1,1194 @@
+/*
+ File: DNSServiceDiscoveryPref.m
+
+ Abstract: System Preference Pane for Dynamic DNS and Wide-Area DNS Service Discovery
+
+ Copyright: (c) Copyright 2005-2011 Apple Computer, Inc. All rights reserved.
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
+ ("Apple") in consideration of your agreement to the following terms, and your
+ use, installation, modification or redistribution of this Apple software
+ constitutes acceptance of these terms. If you do not agree with these terms,
+ please do not use, install, modify or redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject
+ to these terms, Apple grants you a personal, non-exclusive license, under Apple's
+ copyrights in this original Apple software (the "Apple Software"), to use,
+ reproduce, modify and redistribute the Apple Software, with or without
+ modifications, in source and/or binary forms; provided that if you redistribute
+ the Apple Software in its entirety and without modifications, you must retain
+ this notice and the following text and disclaimers in all such redistributions of
+ the Apple Software. Neither the name, trademarks, service marks or logos of
+ Apple Computer, Inc. may be used to endorse or promote products derived from the
+ Apple Software without specific prior written permission from Apple. Except as
+ expressly stated in this notice, no other rights or licenses, express or implied,
+ are granted by Apple herein, including but not limited to any patent rights that
+ may be infringed by your derivative works or by other works in which the Apple
+ Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "DNSServiceDiscoveryPref.h"
+#import "ConfigurationAuthority.h"
+#import "PrivilegedOperations.h"
+#import <unistd.h>
+
+#include "../../Clients/ClientCommon.h"
+
+#ifndef NSINTEGER_DEFINED
+#define NSInteger int
+#endif
+
+@implementation DNSServiceDiscoveryPref
+
+static NSInteger
+MyArrayCompareFunction(id val1, id val2, void *context)
+{
+ (void)context; // Unused
+ return CFStringCompare((CFStringRef)val1, (CFStringRef)val2, kCFCompareCaseInsensitive);
+}
+
+static NSInteger
+MyDomainArrayCompareFunction(id val1, id val2, void *context)
+{
+ (void)context; // Unused
+ NSString *domain1 = [val1 objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
+ NSString *domain2 = [val2 objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
+ return CFStringCompare((CFStringRef)domain1, (CFStringRef)domain2, kCFCompareCaseInsensitive);
+}
+
+
+static void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
+{
+ (void)store; // Unused
+ (void)changedKeys; // Unused
+ DNSServiceDiscoveryPref * me = (DNSServiceDiscoveryPref *)context;
+ assert(me != NULL);
+
+ [me setupInitialValues];
+}
+
+
+static void ServiceDomainEnumReply( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode, const char *replyDomain, void *context, DNSServiceFlags enumType)
+{
+ (void)sdRef; // Unused
+ (void)interfaceIndex; // Unused
+ (void)errorCode; // Unused
+ if (strcmp(replyDomain, "local.") == 0) return; // local domain is not interesting
+
+ DNSServiceDiscoveryPref * me = (DNSServiceDiscoveryPref *)context;
+ BOOL moreComing = (BOOL)(flags & kDNSServiceFlagsMoreComing);
+ NSMutableArray * domainArray;
+ NSMutableArray * defaultBrowseDomainsArray = nil;
+ NSComboBox * domainComboBox;
+ NSString * domainString;
+ NSString * currentDomain = nil;
+ char decodedDomainString[kDNSServiceMaxDomainName] = "\0";
+ char nextLabel[256] = "\0";
+ char * buffer = (char *)replyDomain;
+
+ while (*buffer) {
+ buffer = (char *)GetNextLabel(buffer, nextLabel);
+ strcat(decodedDomainString, nextLabel);
+ strcat(decodedDomainString, ".");
+ }
+
+ // Remove trailing dot from domain name.
+ decodedDomainString[strlen(decodedDomainString)-1] = '\0';
+
+ domainString = [[[NSString alloc] initWithUTF8String:(const char *)decodedDomainString] autorelease];
+
+ if (enumType & kDNSServiceFlagsRegistrationDomains) {
+ domainArray = [me registrationDataSource];
+ domainComboBox = [me regDomainsComboBox];
+ currentDomain = [me currentRegDomain];
+ } else {
+ domainArray = [me browseDataSource];
+ domainComboBox = [me browseDomainsComboBox];
+ defaultBrowseDomainsArray = [me defaultBrowseDomainsArray];
+ }
+
+ if (flags & kDNSServiceFlagsAdd) {
+ [domainArray removeObject:domainString]; // How can I check if an object is in the array?
+ [domainArray addObject:domainString];
+ if ((flags & kDNSServiceFlagsDefault) && (enumType & kDNSServiceFlagsRegistrationDomains)) {
+ [me setDefaultRegDomain:domainString];
+ if ([[domainComboBox stringValue] length] == 0) [domainComboBox setStringValue:domainString];
+ } else if ((flags & kDNSServiceFlagsDefault) && !(enumType & kDNSServiceFlagsRegistrationDomains)) {
+ [defaultBrowseDomainsArray removeObject:domainString];
+ [defaultBrowseDomainsArray addObject:domainString];
+ }
+ }
+
+ if (moreComing == NO) {
+ [domainArray sortUsingFunction:MyArrayCompareFunction context:nil];
+ [domainComboBox reloadData];
+ }
+}
+
+
+static void
+browseDomainReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode, const char *replyDomain, void *context)
+{
+ ServiceDomainEnumReply(sdRef, flags, interfaceIndex, errorCode, replyDomain, context, kDNSServiceFlagsBrowseDomains);
+}
+
+
+static void
+registrationDomainReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode, const char *replyDomain, void *context)
+{
+ ServiceDomainEnumReply(sdRef, flags, interfaceIndex, errorCode, replyDomain, context, kDNSServiceFlagsRegistrationDomains);
+}
+
+
+
+static void
+MyDNSServiceCleanUp(MyDNSServiceState * query)
+{
+ /* Remove the CFRunLoopSource from the current run loop. */
+ CFRunLoopRemoveSource(CFRunLoopGetCurrent(), query->source, kCFRunLoopCommonModes);
+ CFRelease(query->source);
+
+ /* Invalidate the CFSocket. */
+ CFSocketInvalidate(query->socket);
+ CFRelease(query->socket);
+
+ /* Workaround that gives time to CFSocket's select thread so it can remove the socket from its FD set
+ before we close the socket by calling DNSServiceRefDeallocate. <rdar://problem/3585273> */
+ usleep(1000);
+
+ /* Terminate the connection with the mDNSResponder daemon, which cancels the query. */
+ DNSServiceRefDeallocate(query->service);
+}
+
+
+
+static void
+MySocketReadCallback(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void * data, void * info)
+{
+ #pragma unused(s)
+ #pragma unused(type)
+ #pragma unused(address)
+ #pragma unused(data)
+
+ DNSServiceErrorType err;
+
+ MyDNSServiceState * query = (MyDNSServiceState *)info; // context passed in to CFSocketCreateWithNative().
+ assert(query != NULL);
+
+ /* Read a reply from the mDNSResponder. */
+ err= DNSServiceProcessResult(query->service);
+ if (err != kDNSServiceErr_NoError) {
+ fprintf(stderr, "DNSServiceProcessResult returned %d\n", err);
+
+ /* Terminate the query operation and release the CFRunLoopSource and CFSocket. */
+ MyDNSServiceCleanUp(query);
+ }
+}
+
+
+
+static void
+MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
+{
+ CFSocketNativeHandle sock;
+ CFOptionFlags sockFlags;
+ CFSocketContext context = { 0, query, NULL, NULL, NULL }; // Use MyDNSServiceState as context data.
+
+ /* Access the underlying Unix domain socket to communicate with the mDNSResponder daemon. */
+ sock = DNSServiceRefSockFD(query->service);
+ assert(sock != -1);
+
+ /* Create a CFSocket using the Unix domain socket. */
+ query->socket = CFSocketCreateWithNative(NULL, sock, kCFSocketReadCallBack, MySocketReadCallback, &context);
+ assert(query->socket != NULL);
+
+ /* Prevent CFSocketInvalidate from closing DNSServiceRef's socket. */
+ sockFlags = CFSocketGetSocketFlags(query->socket);
+ CFSocketSetSocketFlags(query->socket, sockFlags & (~kCFSocketCloseOnInvalidate));
+
+ /* Create a CFRunLoopSource from the CFSocket. */
+ query->source = CFSocketCreateRunLoopSource(NULL, query->socket, 0);
+ assert(query->source != NULL);
+
+ /* Add the CFRunLoopSource to the current run loop. */
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), query->source, kCFRunLoopCommonModes);
+}
+
+
+
+-(void)updateStatusImageView
+{
+ int value = [self statusForHostName:currentHostName];
+ if (value == 0) [statusImageView setImage:successImage];
+ else if (value > 0) [statusImageView setImage:inprogressImage];
+ else [statusImageView setImage:failureImage];
+}
+
+
+- (void)watchForPreferenceChanges
+{
+ SCDynamicStoreContext context = { 0, self, NULL, NULL, NULL };
+ SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("watchForPreferenceChanges"), NetworkChanged, &context);
+ CFMutableArrayRef keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ CFRunLoopSourceRef rls;
+
+ assert(store != NULL);
+ assert(keys != NULL);
+
+ CFArrayAppendValue(keys, SC_DYNDNS_STATE_KEY);
+ CFArrayAppendValue(keys, SC_DYNDNS_SETUP_KEY);
+
+ (void)SCDynamicStoreSetNotificationKeys(store, keys, NULL);
+
+ rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
+ assert(rls != NULL);
+
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopCommonModes);
+
+ CFRelease(keys);
+ CFRelease(store);
+}
+
+
+-(int)statusForHostName:(NSString * )domain
+{
+ SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("statusForHostName"), NULL, NULL);
+ NSString *lowercaseDomain = [domain lowercaseString];
+ int status = 1;
+
+ assert(store != NULL);
+
+ NSDictionary *dynamicDNS = (NSDictionary *)SCDynamicStoreCopyValue(store, SC_DYNDNS_STATE_KEY);
+ if (dynamicDNS) {
+ NSDictionary *hostNames = [dynamicDNS objectForKey:(NSString *)SC_DYNDNS_HOSTNAMES_KEY];
+ NSDictionary *infoDict = [hostNames objectForKey:lowercaseDomain];
+ if (infoDict) status = [[infoDict objectForKey:(NSString*)SC_DYNDNS_STATUS_KEY] intValue];
+ CFRelease(dynamicDNS);
+ }
+ CFRelease(store);
+
+ return status;
+}
+
+
+- (void)startDomainBrowsing
+{
+ DNSServiceFlags flags;
+ OSStatus err = noErr;
+
+ flags = kDNSServiceFlagsRegistrationDomains;
+ err = DNSServiceEnumerateDomains(&regQuery.service, flags, 0, registrationDomainReply, (void *)self);
+ if (err == kDNSServiceErr_NoError) MyDNSServiceAddServiceToRunLoop(&regQuery);
+
+ flags = kDNSServiceFlagsBrowseDomains;
+ err = DNSServiceEnumerateDomains(&browseQuery.service, flags, 0, browseDomainReply, (void *)self);
+ if (err == kDNSServiceErr_NoError) MyDNSServiceAddServiceToRunLoop(&browseQuery);
+}
+
+
+-(void)readPreferences
+{
+ NSDictionary *origDict;
+ NSArray *regDomainArray;
+ NSArray *hostArray;
+
+ if (currentRegDomain) [currentRegDomain release];
+ if (currentBrowseDomainsArray) [currentBrowseDomainsArray release];
+ if (currentHostName) [currentHostName release];
+
+ SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("com.apple.preference.bonjour"), NULL, NULL);
+ origDict = (NSDictionary *)SCDynamicStoreCopyValue(store, SC_DYNDNS_SETUP_KEY);
+
+ regDomainArray = [origDict objectForKey:(NSString *)SC_DYNDNS_REGDOMAINS_KEY];
+ if (regDomainArray && [regDomainArray count] > 0) {
+ currentRegDomain = [[[regDomainArray objectAtIndex:0] objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY] copy];
+ currentWideAreaState = [[[regDomainArray objectAtIndex:0] objectForKey:(NSString *)SC_DYNDNS_ENABLED_KEY] intValue];
+ } else {
+ currentRegDomain = [[NSString alloc] initWithString:@""];
+ currentWideAreaState = NO;
+ }
+
+ currentBrowseDomainsArray = [[origDict objectForKey:(NSString *)SC_DYNDNS_BROWSEDOMAINS_KEY] retain];
+
+ hostArray = [origDict objectForKey:(NSString *)SC_DYNDNS_HOSTNAMES_KEY];
+ if (hostArray && [hostArray count] > 0) {
+ currentHostName = [[[hostArray objectAtIndex:0] objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY] copy];
+ } else {
+ currentHostName = [[NSString alloc] initWithString:@""];
+ }
+
+ [origDict release];
+ CFRelease(store);
+}
+
+
+- (void)tableViewSelectionDidChange:(NSNotification *)notification
+{
+ [removeBrowseDomainButton setEnabled:[[notification object] numberOfSelectedRows]];
+}
+
+
+- (void)setBrowseDomainsComboBox
+{
+ NSString * domain = nil;
+
+ if ([defaultBrowseDomainsArray count] > 0) {
+ NSEnumerator * arrayEnumerator = [defaultBrowseDomainsArray objectEnumerator];
+ while ((domain = [arrayEnumerator nextObject]) != NULL) {
+ if ([self domainAlreadyInList:domain] == NO) break;
+ }
+ }
+ if (domain) [browseDomainsComboBox setStringValue:domain];
+ else [browseDomainsComboBox setStringValue:@""];
+}
+
+
+- (IBAction)addBrowseDomainClicked:(id)sender
+{
+ [self setBrowseDomainsComboBox];
+
+ [NSApp beginSheet:addBrowseDomainWindow modalForWindow:mainWindow modalDelegate:self
+ didEndSelector:@selector(addBrowseDomainSheetDidEnd:returnCode:contextInfo:) contextInfo:sender];
+
+ [browseDomainList deselectAll:sender];
+ [self updateApplyButtonState];
+}
+
+
+- (IBAction)removeBrowseDomainClicked:(id)sender
+{
+ (void)sender; // Unused
+ int selectedBrowseDomain = [browseDomainList selectedRow];
+ [browseDomainsArray removeObjectAtIndex:selectedBrowseDomain];
+ [browseDomainList reloadData];
+ [self updateApplyButtonState];
+}
+
+
+- (IBAction)enableBrowseDomainClicked:(id)sender
+{
+ NSTableView *tableView = sender;
+ NSMutableDictionary *browseDomainDict;
+ int value;
+
+ browseDomainDict = [[browseDomainsArray objectAtIndex:[tableView clickedRow]] mutableCopy];
+ value = [[browseDomainDict objectForKey:(NSString *)SC_DYNDNS_ENABLED_KEY] intValue];
+ [browseDomainDict setObject:[[[NSNumber alloc] initWithInt:(!value)] autorelease] forKey:(NSString *)SC_DYNDNS_ENABLED_KEY];
+ [browseDomainsArray replaceObjectAtIndex:[tableView clickedRow] withObject:browseDomainDict];
+ [tableView reloadData];
+ [self updateApplyButtonState];
+}
+
+
+
+- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
+{
+ (void)tableView; // Unused
+ int numberOfRows = 0;
+
+ if (browseDomainsArray) {
+ numberOfRows = [browseDomainsArray count];
+ }
+ return numberOfRows;
+}
+
+
+- (void)tabView:(NSTabView *)xtabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem
+{
+ (void)xtabView; // Unused
+ (void)tabViewItem; // Unused
+ [browseDomainList deselectAll:self];
+ [mainWindow makeFirstResponder:nil];
+}
+
+
+- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
+{
+ (void)tableView; // Unused
+ NSDictionary *browseDomainDict;
+ id value = nil;
+
+ if (browseDomainsArray) {
+ browseDomainDict = [browseDomainsArray objectAtIndex:row];
+ if (browseDomainDict) {
+ if ([[tableColumn identifier] isEqualTo:(NSString *)SC_DYNDNS_ENABLED_KEY]) {
+ value = [browseDomainDict objectForKey:(NSString *)SC_DYNDNS_ENABLED_KEY];
+ } else if ([[tableColumn identifier] isEqualTo:(NSString *)SC_DYNDNS_DOMAIN_KEY]) {
+ value = [browseDomainDict objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
+ }
+ }
+ }
+ return value;
+}
+
+
+- (void)setupInitialValues
+{
+ [self readPreferences];
+
+ if (currentHostName) {
+ [hostName setStringValue:currentHostName];
+ [self updateStatusImageView];
+ }
+
+ if (browseDomainsArray) {
+ [browseDomainsArray release];
+ browseDomainsArray = nil;
+ }
+
+ if (currentBrowseDomainsArray) {
+ browseDomainsArray = [currentBrowseDomainsArray mutableCopy];
+ if (browseDomainsArray) {
+ [browseDomainsArray sortUsingFunction:MyDomainArrayCompareFunction context:nil];
+ if ([browseDomainsArray isEqualToArray:currentBrowseDomainsArray] == NO) {
+ OSStatus err = WriteBrowseDomain((CFDataRef)[self dataForDomainArray:browseDomainsArray]);
+ if (err != noErr) NSLog(@"WriteBrowseDomain returned %d\n", (int32_t)err);
+ [currentBrowseDomainsArray release];
+ currentBrowseDomainsArray = [browseDomainsArray copy];
+ }
+ }
+ } else {
+ browseDomainsArray = nil;
+ }
+ [browseDomainList reloadData];
+
+ if (currentRegDomain && ([currentRegDomain length] > 0)) {
+ [regDomainsComboBox setStringValue:currentRegDomain];
+ [registrationDataSource removeObject:currentRegDomain];
+ [registrationDataSource addObject:currentRegDomain];
+ [registrationDataSource sortUsingFunction:MyArrayCompareFunction context:nil];
+ [regDomainsComboBox reloadData];
+ }
+
+ if (currentWideAreaState) {
+ [self toggleWideAreaBonjour:YES];
+ } else {
+ [self toggleWideAreaBonjour:NO];
+ }
+
+ if (hostNameSharedSecretValue) {
+ [hostNameSharedSecretValue release];
+ hostNameSharedSecretValue = nil;
+ }
+
+ if (regSharedSecretValue) {
+ [regSharedSecretValue release];
+ regSharedSecretValue = nil;
+ }
+
+ [self updateApplyButtonState];
+ [mainWindow makeFirstResponder:nil];
+ [browseDomainList deselectAll:self];
+ [removeBrowseDomainButton setEnabled:NO];
+}
+
+
+
+- (void)awakeFromNib
+{
+ OSStatus err;
+
+ prefsNeedUpdating = NO;
+ toolInstalled = NO;
+ browseDomainListEnabled = NO;
+ defaultRegDomain = nil;
+ currentRegDomain = nil;
+ currentBrowseDomainsArray = nil;
+ currentHostName = nil;
+ hostNameSharedSecretValue = nil;
+ regSharedSecretValue = nil;
+ browseDomainsArray = nil;
+ justStartedEditing = YES;
+ currentWideAreaState = NO;
+ NSString *successPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"success" ofType:@"tiff"];
+ NSString *inprogressPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"inprogress" ofType:@"tiff"];
+ NSString *failurePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"failure" ofType:@"tiff"];
+
+ registrationDataSource = [[NSMutableArray alloc] init];
+ browseDataSource = [[NSMutableArray alloc] init];
+ defaultBrowseDomainsArray = [[NSMutableArray alloc] init];
+ successImage = [[NSImage alloc] initWithContentsOfFile:successPath];
+ inprogressImage = [[NSImage alloc] initWithContentsOfFile:inprogressPath];
+ failureImage = [[NSImage alloc] initWithContentsOfFile:failurePath];
+
+ [tabView selectFirstTabViewItem:self];
+ [self setupInitialValues];
+ [self startDomainBrowsing];
+ [self watchForPreferenceChanges];
+
+ InitConfigAuthority();
+ err = EnsureToolInstalled();
+ if (err == noErr) toolInstalled = YES;
+ else { long int tmp = err; fprintf(stderr, "EnsureToolInstalled returned %ld\n", tmp); }
+
+}
+
+
+- (IBAction)closeMyCustomSheet:(id)sender
+{
+ BOOL result = [sender isEqualTo:browseOKButton] || [sender isEqualTo:secretOKButton];
+
+ if (result) [NSApp endSheet:[sender window] returnCode:NSOKButton];
+ else [NSApp endSheet:[sender window] returnCode:NSCancelButton];
+}
+
+
+- (void)sharedSecretSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
+{
+ NSButton * button = (NSButton *)contextInfo;
+ [sheet orderOut:self];
+ [self enableControls];
+
+ if (returnCode == NSOKButton) {
+ if ([button isEqualTo:hostNameSharedSecretButton]) {
+ hostNameSharedSecretName = [[NSString alloc] initWithString:[sharedSecretName stringValue]];
+ hostNameSharedSecretValue = [[NSString alloc] initWithString:[sharedSecretValue stringValue]];
+ } else {
+ regSharedSecretName = [[NSString alloc] initWithString:[sharedSecretName stringValue]];
+ regSharedSecretValue = [[NSString alloc] initWithString:[sharedSecretValue stringValue]];
+ }
+ [self updateApplyButtonState];
+ }
+ [sharedSecretValue setStringValue:@""];
+}
+
+
+- (BOOL)domainAlreadyInList:(NSString *)domainString
+{
+ if (browseDomainsArray) {
+ NSDictionary *domainDict;
+ NSString *domainName;
+ NSEnumerator *arrayEnumerator = [browseDomainsArray objectEnumerator];
+ while ((domainDict = [arrayEnumerator nextObject]) != NULL) {
+ domainName = [domainDict objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
+ if ([domainString caseInsensitiveCompare:domainName] == NSOrderedSame) return YES;
+ }
+ }
+ return NO;
+}
+
+
+- (NSString *)trimCharactersFromDomain:(NSString *)domain
+{
+ NSMutableCharacterSet * trimSet = [[[NSCharacterSet whitespaceCharacterSet] mutableCopy] autorelease];
+ [trimSet formUnionWithCharacterSet:[NSCharacterSet punctuationCharacterSet]];
+ return [domain stringByTrimmingCharactersInSet:trimSet];
+}
+
+
+- (void)addBrowseDomainSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
+{
+ (void)contextInfo; // Unused
+ [sheet orderOut:self];
+ [self enableControls];
+
+ if (returnCode == NSOKButton) {
+ NSString * newBrowseDomainString = [self trimCharactersFromDomain:[browseDomainsComboBox stringValue]];
+ NSMutableDictionary *newBrowseDomainDict;
+
+ if (browseDomainsArray == nil) browseDomainsArray = [[NSMutableArray alloc] initWithCapacity:0];
+ if ([self domainAlreadyInList:newBrowseDomainString] == NO) {
+ newBrowseDomainDict = [[[NSMutableDictionary alloc] initWithCapacity:2] autorelease];
+
+ [newBrowseDomainDict setObject:newBrowseDomainString forKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
+ [newBrowseDomainDict setObject:[[[NSNumber alloc] initWithBool:YES] autorelease] forKey:(NSString *)SC_DYNDNS_ENABLED_KEY];
+
+ [browseDomainsArray addObject:newBrowseDomainDict];
+ [browseDomainsArray sortUsingFunction:MyDomainArrayCompareFunction context:nil];
+ [browseDomainList reloadData];
+ [self updateApplyButtonState];
+ }
+ }
+}
+
+
+-(void)validateTextFields
+{
+ [hostName validateEditing];
+ [browseDomainsComboBox validateEditing];
+ [regDomainsComboBox validateEditing];
+}
+
+
+- (IBAction)changeButtonPressed:(id)sender
+{
+ NSString * keyName;
+
+ [self disableControls];
+ [self validateTextFields];
+ [mainWindow makeFirstResponder:nil];
+ [browseDomainList deselectAll:sender];
+
+ if ([sender isEqualTo:hostNameSharedSecretButton]) {
+ if (hostNameSharedSecretValue) {
+ [sharedSecretValue setStringValue:hostNameSharedSecretValue];
+ } else if ((keyName = [self sharedSecretKeyName:[hostName stringValue]]) != NULL) {
+ [sharedSecretName setStringValue:keyName];
+ [sharedSecretValue setStringValue:@"****************"];
+ } else {
+ [sharedSecretName setStringValue:[hostName stringValue]];
+ [sharedSecretValue setStringValue:@""];
+ }
+
+ } else {
+ if (regSharedSecretValue) {
+ [sharedSecretValue setStringValue:regSharedSecretValue];
+ } else if ((keyName = [self sharedSecretKeyName:[regDomainsComboBox stringValue]]) != NULL) {
+ [sharedSecretName setStringValue:keyName];
+ [sharedSecretValue setStringValue:@"****************"];
+ } else {
+ [sharedSecretName setStringValue:[regDomainsComboBox stringValue]];
+ [sharedSecretValue setStringValue:@""];
+ }
+ }
+
+ [sharedSecretWindow resignFirstResponder];
+
+ if ([[sharedSecretName stringValue] length] > 0) [sharedSecretWindow makeFirstResponder:sharedSecretValue];
+ else [sharedSecretWindow makeFirstResponder:sharedSecretName];
+
+ [NSApp beginSheet:sharedSecretWindow modalForWindow:mainWindow modalDelegate:self
+ didEndSelector:@selector(sharedSecretSheetDidEnd:returnCode:contextInfo:) contextInfo:sender];
+}
+
+
+- (IBAction)wideAreaCheckBoxChanged:(id)sender
+{
+ [self toggleWideAreaBonjour:[sender state]];
+ [self updateApplyButtonState];
+ [mainWindow makeFirstResponder:nil];
+}
+
+
+- (void)updateApplyButtonState
+{
+ NSString *hostNameString = [hostName stringValue];
+ NSString *regDomainString = [regDomainsComboBox stringValue];
+
+ NSComparisonResult hostNameResult = [hostNameString compare:currentHostName];
+ NSComparisonResult regDomainResult = [regDomainString compare:currentRegDomain];
+
+ if ((currentHostName && (hostNameResult != NSOrderedSame)) ||
+ (currentRegDomain && (regDomainResult != NSOrderedSame) && ([wideAreaCheckBox state])) ||
+ (currentHostName == nil && ([hostNameString length]) > 0) ||
+ (currentRegDomain == nil && ([regDomainString length]) > 0) ||
+ (currentWideAreaState != [wideAreaCheckBox state]) ||
+ (hostNameSharedSecretValue != nil) ||
+ (regSharedSecretValue != nil) ||
+ (browseDomainsArray && [browseDomainsArray isEqualToArray:currentBrowseDomainsArray] == NO))
+ {
+ [self enableApplyButton];
+ } else {
+ [self disableApplyButton];
+ }
+}
+
+
+
+- (void)controlTextDidChange:(NSNotification *)notification
+{
+ (void)notification; // Unused
+ [self updateApplyButtonState];
+}
+
+
+
+- (IBAction)comboAction:(id)sender
+{
+ (void)sender; // Unused
+ [self updateApplyButtonState];
+}
+
+
+- (id)comboBox:(NSComboBox *)aComboBox objectValueForItemAtIndex:(int)ind
+{
+ NSString *domain = nil;
+ if ([aComboBox isEqualTo:browseDomainsComboBox]) domain = [browseDataSource objectAtIndex:ind];
+ else if ([aComboBox isEqualTo:regDomainsComboBox]) domain = [registrationDataSource objectAtIndex:ind];
+ return domain;
+}
+
+
+
+- (int)numberOfItemsInComboBox:(NSComboBox *)aComboBox
+{
+ int count = 0;
+ if ([aComboBox isEqualTo:browseDomainsComboBox]) count = [browseDataSource count];
+ else if ([aComboBox isEqualTo:regDomainsComboBox]) count = [registrationDataSource count];
+ return count;
+}
+
+
+- (NSMutableArray *)browseDataSource
+{
+ return browseDataSource;
+}
+
+
+- (NSMutableArray *)registrationDataSource
+{
+ return registrationDataSource;
+}
+
+
+- (NSComboBox *)browseDomainsComboBox
+{
+ return browseDomainsComboBox;
+}
+
+
+- (NSComboBox *)regDomainsComboBox
+{
+ return regDomainsComboBox;
+}
+
+
+- (NSString *)currentRegDomain
+{
+ return currentRegDomain;
+}
+
+
+- (NSMutableArray *)defaultBrowseDomainsArray
+{
+ return defaultBrowseDomainsArray;
+}
+
+
+- (NSArray *)currentBrowseDomainsArray
+{
+ return currentBrowseDomainsArray;
+}
+
+
+- (NSString *)currentHostName
+{
+ return currentHostName;
+}
+
+
+- (NSString *)defaultRegDomain
+{
+ return defaultRegDomain;
+}
+
+
+- (void)setDefaultRegDomain:(NSString *)domain
+{
+ [defaultRegDomain release];
+ defaultRegDomain = domain;
+ [defaultRegDomain retain];
+}
+
+
+- (void)didSelect
+{
+ [super didSelect];
+ mainWindow = [[self mainView] window];
+}
+
+
+- (void)mainViewDidLoad
+{
+ [comboAuthButton setString:"system.preferences"];
+ [comboAuthButton setDelegate:self];
+ [comboAuthButton updateStatus:nil];
+ [comboAuthButton setAutoupdate:YES];
+}
+
+
+
+- (IBAction)applyClicked:(id)sender
+{
+ (void)sender; // Unused
+ [self applyCurrentState];
+}
+
+
+- (void)applyCurrentState
+{
+ [self validateTextFields];
+
+ if (toolInstalled == YES) {
+ [self savePreferences];
+ [self disableApplyButton];
+ [mainWindow makeFirstResponder:nil];
+ }
+}
+
+
+- (void)enableApplyButton
+{
+ [applyButton setEnabled:YES];
+ [revertButton setEnabled:YES];
+ prefsNeedUpdating = YES;
+}
+
+
+- (void)disableApplyButton
+{
+ [applyButton setEnabled:NO];
+ [revertButton setEnabled:NO];
+ prefsNeedUpdating = NO;
+}
+
+
+- (void)toggleWideAreaBonjour:(BOOL)state
+{
+ [wideAreaCheckBox setState:state];
+ [regDomainsComboBox setEnabled:state];
+ [registrationSharedSecretButton setEnabled:state];
+}
+
+
+- (IBAction)revertClicked:(id)sender
+{
+ [self restorePreferences];
+ [browseDomainList deselectAll:sender];
+ [mainWindow makeFirstResponder:nil];
+}
+
+
+- (void)restorePreferences
+{
+ [self setupInitialValues];
+}
+
+
+- (void)savePanelWillClose:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
+{
+ (void)sheet; // Unused
+ DNSServiceDiscoveryPref * me = (DNSServiceDiscoveryPref *)contextInfo;
+
+ if (returnCode == NSAlertDefaultReturn) {
+ [me applyCurrentState];
+ } else if (returnCode == NSAlertAlternateReturn ) {
+ [me restorePreferences];
+ }
+
+ [me enableControls];
+ [me replyToShouldUnselect:(returnCode != NSAlertOtherReturn)];
+}
+
+
+-(SecKeychainItemRef)copyKeychainItemforDomain:(NSString *)domain
+{
+ const char * serviceName = [domain UTF8String];
+ UInt32 type = 'ddns';
+ UInt32 typeLength = sizeof(type);
+
+ SecKeychainAttribute attrs[] = { { kSecServiceItemAttr, strlen(serviceName), (char *)serviceName },
+ { kSecTypeItemAttr, typeLength, (UInt32 *)&type } };
+
+ SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs };
+ SecKeychainSearchRef searchRef;
+ SecKeychainItemRef itemRef = NULL;
+ OSStatus err;
+
+ err = SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, &attributes, &searchRef);
+ if (err == noErr) {
+ err = SecKeychainSearchCopyNext(searchRef, &itemRef);
+ if (err != noErr) itemRef = NULL;
+ }
+ return itemRef;
+}
+
+
+-(NSString *)sharedSecretKeyName:(NSString * )domain
+{
+ SecKeychainItemRef itemRef = NULL;
+ NSString *keyName = nil;
+ OSStatus err;
+
+ err = SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
+ assert(err == noErr);
+
+ itemRef = [self copyKeychainItemforDomain:[domain lowercaseString]];
+ if (itemRef) {
+ UInt32 tags[1];
+ SecKeychainAttributeInfo attrInfo;
+ SecKeychainAttributeList *attrList = NULL;
+ SecKeychainAttribute attribute;
+ unsigned int i;
+
+ tags[0] = kSecAccountItemAttr;
+ attrInfo.count = 1;
+ attrInfo.tag = tags;
+ attrInfo.format = NULL;
+
+ err = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL, &attrList, NULL, NULL);
+ if (err == noErr) {
+ for (i = 0; i < attrList->count; i++) {
+ attribute = attrList->attr[i];
+ if (attribute.tag == kSecAccountItemAttr) {
+ keyName = [[NSString alloc] initWithBytes:attribute.data length:attribute.length encoding:NSUTF8StringEncoding];
+ break;
+ }
+ }
+ if (attrList) (void)SecKeychainItemFreeAttributesAndData(attrList, NULL);
+ }
+ CFRelease(itemRef);
+ }
+ return keyName;
+}
+
+
+-(NSString *)domainForHostName:(NSString *)hostNameString
+{
+ NSString * domainName = nil;
+ char text[64];
+ char * ptr = NULL;
+
+ ptr = (char *)[hostNameString UTF8String];
+ if (ptr) {
+ ptr = (char *)GetNextLabel(ptr, text);
+ domainName = [[NSString alloc] initWithUTF8String:(const char *)ptr];
+ }
+ return ([domainName autorelease]);
+}
+
+
+- (NSData *)dataForDomain:(NSString *)domainName isEnabled:(BOOL)enabled
+{
+ NSMutableArray *domainsArray;
+ NSMutableDictionary *domainDict = nil;
+
+ if (domainName && [domainName length] > 0) {
+ domainDict= [[[NSMutableDictionary alloc] initWithCapacity:2] autorelease];
+ [domainDict setObject:domainName forKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
+ [domainDict setObject:[[[NSNumber alloc] initWithBool:enabled] autorelease] forKey:(NSString *)SC_DYNDNS_ENABLED_KEY];
+ }
+ domainsArray = [[[NSMutableArray alloc] initWithCapacity:1] autorelease];
+ if (domainDict) [domainsArray addObject:domainDict];
+ return [NSArchiver archivedDataWithRootObject:domainsArray];
+}
+
+
+- (NSData *)dataForDomainArray:(NSArray *)domainArray
+{
+ return [NSArchiver archivedDataWithRootObject:domainArray];
+}
+
+
+- (NSData *)dataForSharedSecret:(NSString *)secret domain:(NSString *)domainName key:(NSString *)keyName
+{
+ NSMutableDictionary *sharedSecretDict = [[[NSMutableDictionary alloc] initWithCapacity:3] autorelease];
+ [sharedSecretDict setObject:secret forKey:(NSString *)SC_DYNDNS_SECRET_KEY];
+ [sharedSecretDict setObject:[domainName lowercaseString] forKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
+ [sharedSecretDict setObject:keyName forKey:(NSString *)SC_DYNDNS_KEYNAME_KEY];
+ return [NSArchiver archivedDataWithRootObject:sharedSecretDict];
+}
+
+
+-(void)savePreferences
+{
+ NSString *hostNameString = [hostName stringValue];
+ NSString *browseDomainString = [browseDomainsComboBox stringValue];
+ NSString *regDomainString = [regDomainsComboBox stringValue];
+ NSString *tempHostNameSharedSecretName = hostNameSharedSecretName;
+ NSString *tempRegSharedSecretName = regSharedSecretName;
+ NSData *browseDomainData = nil;
+ BOOL regSecretWasSet = NO;
+ BOOL hostSecretWasSet = NO;
+ OSStatus err = noErr;
+
+ hostNameString = [self trimCharactersFromDomain:hostNameString];
+ browseDomainString = [self trimCharactersFromDomain:browseDomainString];
+ regDomainString = [self trimCharactersFromDomain:regDomainString];
+ tempHostNameSharedSecretName = [self trimCharactersFromDomain:tempHostNameSharedSecretName];
+ tempRegSharedSecretName = [self trimCharactersFromDomain:tempRegSharedSecretName];
+
+ [hostName setStringValue:hostNameString];
+ [regDomainsComboBox setStringValue:regDomainString];
+
+ // Convert Shared Secret account names to lowercase.
+ tempHostNameSharedSecretName = [tempHostNameSharedSecretName lowercaseString];
+ tempRegSharedSecretName = [tempRegSharedSecretName lowercaseString];
+
+ // Save hostname shared secret.
+ if ([hostNameSharedSecretName length] > 0 && ([hostNameSharedSecretValue length] > 0)) {
+ SetKeyForDomain((CFDataRef)[self dataForSharedSecret:hostNameSharedSecretValue domain:hostNameString key:tempHostNameSharedSecretName]);
+ [hostNameSharedSecretValue release];
+ hostNameSharedSecretValue = nil;
+ hostSecretWasSet = YES;
+ }
+
+ // Save registration domain shared secret.
+ if (([regSharedSecretName length] > 0) && ([regSharedSecretValue length] > 0)) {
+ SetKeyForDomain((CFDataRef)[self dataForSharedSecret:regSharedSecretValue domain:regDomainString key:tempRegSharedSecretName]);
+ [regSharedSecretValue release];
+ regSharedSecretValue = nil;
+ regSecretWasSet = YES;
+ }
+
+ // Save hostname.
+ if ((currentHostName == NULL) || [currentHostName compare:hostNameString] != NSOrderedSame) {
+ err = WriteHostname((CFDataRef)[self dataForDomain:hostNameString isEnabled:YES]);
+ if (err != noErr) NSLog(@"WriteHostname returned %d\n", (int32_t)err);
+ currentHostName = [hostNameString copy];
+ } else if (hostSecretWasSet) {
+ WriteHostname((CFDataRef)[self dataForDomain:@"" isEnabled:NO]);
+ usleep(200000); // Temporary hack
+ if ([currentHostName length] > 0) WriteHostname((CFDataRef)[self dataForDomain:(NSString *)currentHostName isEnabled:YES]);
+ }
+
+ // Save browse domain.
+ if (browseDomainsArray && [browseDomainsArray isEqualToArray:currentBrowseDomainsArray] == NO) {
+ browseDomainData = [self dataForDomainArray:browseDomainsArray];
+ err = WriteBrowseDomain((CFDataRef)browseDomainData);
+ if (err != noErr) NSLog(@"WriteBrowseDomain returned %d\n", (int32_t)err);
+ currentBrowseDomainsArray = [browseDomainsArray copy];
+ }
+
+ // Save registration domain.
+ if ((currentRegDomain == NULL) || ([currentRegDomain compare:regDomainString] != NSOrderedSame) || (currentWideAreaState != [wideAreaCheckBox state])) {
+
+ err = WriteRegistrationDomain((CFDataRef)[self dataForDomain:regDomainString isEnabled:[wideAreaCheckBox state]]);
+ if (err != noErr) NSLog(@"WriteRegistrationDomain returned %d\n", (int32_t)err);
+
+ if (currentRegDomain) CFRelease(currentRegDomain);
+ currentRegDomain = [regDomainString copy];
+
+ if ([currentRegDomain length] > 0) {
+ currentWideAreaState = [wideAreaCheckBox state];
+ [registrationDataSource removeObject:regDomainString];
+ [registrationDataSource addObject:currentRegDomain];
+ [registrationDataSource sortUsingFunction:MyArrayCompareFunction context:nil];
+ [regDomainsComboBox reloadData];
+ } else {
+ currentWideAreaState = NO;
+ [self toggleWideAreaBonjour:NO];
+ if (defaultRegDomain != nil) [regDomainsComboBox setStringValue:defaultRegDomain];
+ }
+ } else if (regSecretWasSet) {
+ WriteRegistrationDomain((CFDataRef)[self dataForDomain:@"" isEnabled:NO]);
+ usleep(200000); // Temporary hack
+ if ([currentRegDomain length] > 0) WriteRegistrationDomain((CFDataRef)[self dataForDomain:currentRegDomain isEnabled:currentWideAreaState]);
+ }
+}
+
+
+- (NSPreferencePaneUnselectReply)shouldUnselect
+{
+#if 1
+ if (prefsNeedUpdating == YES) {
+
+ [self disableControls];
+
+ NSBeginAlertSheet(
+ @"Apply Configuration Changes?",
+ @"Apply",
+ @"Don't Apply",
+ @"Cancel",
+ mainWindow,
+ self,
+ @selector( savePanelWillClose:returnCode:contextInfo: ),
+ NULL,
+ (void *) self, // sender,
+ @"" );
+ return NSUnselectLater;
+ }
+#endif
+
+ return NSUnselectNow;
+}
+
+
+-(void)disableControls
+{
+ [hostName setEnabled:NO];
+ [hostNameSharedSecretButton setEnabled:NO];
+ [browseDomainsComboBox setEnabled:NO];
+ [applyButton setEnabled:NO];
+ [revertButton setEnabled:NO];
+ [wideAreaCheckBox setEnabled:NO];
+ [regDomainsComboBox setEnabled:NO];
+ [registrationSharedSecretButton setEnabled:NO];
+ [statusImageView setEnabled:NO];
+
+ browseDomainListEnabled = NO;
+ [browseDomainList deselectAll:self];
+ [browseDomainList setEnabled:NO];
+
+ [addBrowseDomainButton setEnabled:NO];
+ [removeBrowseDomainButton setEnabled:NO];
+}
+
+
+- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row
+{
+ (void)row; // Unused
+ (void)tableView; // Unused
+ return browseDomainListEnabled;
+}
+
+
+-(void)enableControls
+{
+ [hostName setEnabled:YES];
+ [hostNameSharedSecretButton setEnabled:YES];
+ [browseDomainsComboBox setEnabled:YES];
+ [wideAreaCheckBox setEnabled:YES];
+ [registrationSharedSecretButton setEnabled:YES];
+ [self toggleWideAreaBonjour:[wideAreaCheckBox state]];
+ [statusImageView setEnabled:YES];
+ [addBrowseDomainButton setEnabled:YES];
+
+ [browseDomainList setEnabled:YES];
+ [browseDomainList deselectAll:self];
+ browseDomainListEnabled = YES;
+
+ [removeBrowseDomainButton setEnabled:[browseDomainList numberOfSelectedRows]];
+ [applyButton setEnabled:prefsNeedUpdating];
+ [revertButton setEnabled:prefsNeedUpdating];
+}
+
+
+- (void)authorizationViewDidAuthorize:(SFAuthorizationView *)view
+{
+ (void)view; // Unused
+ [self enableControls];
+}
+
+
+- (void)authorizationViewDidDeauthorize:(SFAuthorizationView *)view
+{
+ (void)view; // Unused
+ [self disableControls];
+}
+
+@end
+
+
+// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
+// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
+// To expand "version" to its value before making the string, use STRINGIFY(version) instead
+#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
+#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
+
+// NOT static -- otherwise the compiler may optimize it out
+// The "@(#) " pattern is a special prefix the "what" command looks for
+const char VersionString_SCCS[] = "@(#) Bonjour Preference Pane " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
+
+#if _BUILDING_XCODE_PROJECT_
+// If the process crashes, then this string will be magically included in the automatically-generated crash log
+const char *__crashreporter_info__ = VersionString_SCCS + 5;
+asm(".desc ___crashreporter_info__, 0x10");
+#endif
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib/classes.nib b/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib/classes.nib
new file mode 100644
index 00000000..58c1f3e5
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib/classes.nib
@@ -0,0 +1,59 @@
+{
+ IBClasses = (
+ {
+ ACTIONS = {
+ addBrowseDomainClicked = id;
+ applyClicked = id;
+ changeButtonPressed = id;
+ closeMyCustomSheet = id;
+ comboAction = id;
+ enableBrowseDomainClicked = id;
+ removeBrowseDomainClicked = id;
+ revertClicked = id;
+ wideAreaCheckBoxChanged = id;
+ };
+ CLASS = DNSServiceDiscoveryPref;
+ LANGUAGE = ObjC;
+ OUTLETS = {
+ addBrowseDomainButton = NSButton;
+ addBrowseDomainWindow = NSWindow;
+ applyButton = NSButton;
+ browseCancelButton = NSButton;
+ browseDomainList = NSTableView;
+ browseDomainsComboBox = NSComboBox;
+ browseOKButton = NSButton;
+ comboAuthButton = SFAuthorizationView;
+ hostName = NSTextField;
+ hostNameSharedSecretButton = NSButton;
+ regDomainsComboBox = NSComboBox;
+ registrationSharedSecretButton = NSButton;
+ removeBrowseDomainButton = NSButton;
+ revertButton = NSButton;
+ secretCancelButton = NSButton;
+ secretOKButton = NSButton;
+ sharedSecretName = NSTextField;
+ sharedSecretValue = NSSecureTextField;
+ sharedSecretWindow = NSWindow;
+ statusImageView = NSImageView;
+ tabView = NSTabView;
+ wideAreaCheckBox = NSButton;
+ };
+ SUPERCLASS = NSPreferencePane;
+ },
+ {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
+ {
+ CLASS = NSPreferencePane;
+ LANGUAGE = ObjC;
+ OUTLETS = {
+ "_firstKeyView" = id;
+ "_initialKeyView" = id;
+ "_lastKeyView" = id;
+ "_window" = id;
+ };
+ SUPERCLASS = NSObject;
+ },
+ {CLASS = NSSegmentedControl; LANGUAGE = ObjC; SUPERCLASS = NSControl; },
+ {CLASS = SFAuthorizationView; LANGUAGE = ObjC; SUPERCLASS = NSView; }
+ );
+ IBVersion = 1;
+} \ No newline at end of file
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib/info.nib b/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib/info.nib
new file mode 100644
index 00000000..e8dbd926
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib/info.nib
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>IBDocumentLocation</key>
+ <string>32 63 547 281 0 0 1024 746 </string>
+ <key>IBFramework Version</key>
+ <string>439.0</string>
+ <key>IBOpenObjects</key>
+ <array>
+ <integer>255</integer>
+ <integer>333</integer>
+ <integer>12</integer>
+ </array>
+ <key>IBSystem Version</key>
+ <string>8F23</string>
+</dict>
+</plist>
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib/keyedobjects.nib b/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib/keyedobjects.nib
new file mode 100644
index 00000000..eec01ee4
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib/keyedobjects.nib
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/InfoPlist.strings b/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/InfoPlist.strings
new file mode 100644
index 00000000..e2dfa991
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/InfoPlist.strings
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Info-PreferencePane.plist b/mDNSResponder/mDNSMacOSX/PreferencePane/Info-PreferencePane.plist
new file mode 100644
index 00000000..e5cdb9f2
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/Info-PreferencePane.plist
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>Bonjour</string>
+ <key>CFBundleGetInfoString</key>
+ <string></string>
+ <key>CFBundleIconFile</key>
+ <string>BonjourPref</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.apple.preference.bonjour</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string></string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>NSMainNibFile</key>
+ <string>DNSServiceDiscoveryPref</string>
+ <key>NSPrefPaneIconFile</key>
+ <string>BonjourPref.tiff</string>
+ <key>NSPrefPaneIconLabel</key>
+ <string>Bonjour</string>
+ <key>NSPrincipalClass</key>
+ <string>DNSServiceDiscoveryPref</string>
+</dict>
+</plist>
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/PrivilegedOperations.c b/mDNSResponder/mDNSMacOSX/PreferencePane/PrivilegedOperations.c
new file mode 100644
index 00000000..4c0ffa0e
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/PrivilegedOperations.c
@@ -0,0 +1,230 @@
+/*
+ File: PrivilegedOperations.c
+
+ Abstract: Interface to "ddnswriteconfig" setuid root tool.
+
+ Copyright: (c) Copyright 2005 Apple Computer, Inc. All rights reserved.
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
+ ("Apple") in consideration of your agreement to the following terms, and your
+ use, installation, modification or redistribution of this Apple software
+ constitutes acceptance of these terms. If you do not agree with these terms,
+ please do not use, install, modify or redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject
+ to these terms, Apple grants you a personal, non-exclusive license, under Apple's
+ copyrights in this original Apple software (the "Apple Software"), to use,
+ reproduce, modify and redistribute the Apple Software, with or without
+ modifications, in source and/or binary forms; provided that if you redistribute
+ the Apple Software in its entirety and without modifications, you must retain
+ this notice and the following text and disclaimers in all such redistributions of
+ the Apple Software. Neither the name, trademarks, service marks or logos of
+ Apple Computer, Inc. may be used to endorse or promote products derived from the
+ Apple Software without specific prior written permission from Apple. Except as
+ expressly stated in this notice, no other rights or licenses, express or implied,
+ are granted by Apple herein, including but not limited to any patent rights that
+ may be infringed by your derivative works or by other works in which the Apple
+ Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "PrivilegedOperations.h"
+#include "ConfigurationAuthority.h"
+#include <CoreFoundation/CoreFoundation.h>
+#include <SystemConfiguration/SystemConfiguration.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <AssertMacros.h>
+#include <Security/Security.h>
+
+Boolean gToolApproved = false;
+
+static pid_t execTool(const char *args[])
+// fork/exec and return new pid
+{
+ pid_t child;
+
+ child = vfork();
+ if (child == 0)
+ {
+ execv(args[0], (char *const *)args);
+ printf("exec of %s failed; errno = %d\n", args[0], errno);
+ _exit(-1); // exec failed
+ }
+ else
+ return child;
+}
+
+OSStatus EnsureToolInstalled(void)
+// Make sure that the tool is installed in the right place, with the right privs, and the right version.
+{
+ CFURLRef bundleURL;
+ pid_t toolPID;
+ int status;
+ OSStatus err = noErr;
+ const char *args[] = { kToolPath, "0", "V", NULL };
+ char toolSourcePath[PATH_MAX] = {};
+ char toolInstallerPath[PATH_MAX] = {};
+
+ if (gToolApproved)
+ return noErr;
+
+ // Check version of installed tool
+ toolPID = execTool(args);
+ if (toolPID > 0)
+ {
+ waitpid(toolPID, &status, 0);
+ if (WIFEXITED(status) && WEXITSTATUS(status) == PRIV_OP_TOOL_VERS)
+ return noErr;
+ }
+
+ // Locate our in-bundle copy of privop tool
+ bundleURL = CFBundleCopyBundleURL(CFBundleGetBundleWithIdentifier(CFSTR("com.apple.preference.bonjour")) );
+ if (bundleURL != NULL)
+ {
+ CFURLGetFileSystemRepresentation(bundleURL, false, (UInt8*) toolSourcePath, sizeof toolSourcePath);
+ if (strlcat(toolSourcePath, "/Contents/Resources/" kToolName, sizeof toolSourcePath ) >= sizeof toolSourcePath ) return(-1);
+ CFURLGetFileSystemRepresentation(bundleURL, false, (UInt8*) toolInstallerPath, sizeof toolInstallerPath);
+ if (strlcat(toolInstallerPath, "/Contents/Resources/" kToolInstaller, sizeof toolInstallerPath) >= sizeof toolInstallerPath) return(-1);
+ }
+ else
+ return coreFoundationUnknownErr;
+
+ // Obtain authorization and run in-bundle copy as root to install it
+ {
+ AuthorizationItem aewpRight = { kAuthorizationRightExecute, strlen(toolInstallerPath), toolInstallerPath, 0 };
+ AuthorizationItemSet rights = { 1, &aewpRight };
+ AuthorizationRef authRef;
+
+ err = AuthorizationCreate(&rights, (AuthorizationEnvironment*) NULL,
+ kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights |
+ kAuthorizationFlagPreAuthorize, &authRef);
+ if (err == noErr)
+ {
+ char *installerargs[] = { toolSourcePath, NULL };
+ err = AuthorizationExecuteWithPrivileges(authRef, toolInstallerPath, 0, installerargs, (FILE**) NULL);
+ if (err == noErr) {
+ int pid = wait(&status);
+ if (pid > 0 && WIFEXITED(status)) {
+ err = WEXITSTATUS(status);
+ if (err == noErr) {
+ gToolApproved = true;
+ }
+ } else {
+ err = -1;
+ }
+ }
+ (void) AuthorizationFree(authRef, kAuthorizationFlagDefaults);
+ }
+ }
+
+ return err;
+}
+
+
+static OSStatus ExecWithCmdAndParam(const char *subCmd, CFDataRef paramData)
+// Execute our privop tool with the supplied subCmd and parameter
+{
+ OSStatus err = noErr;
+ int commFD, dataLen;
+ u_int32_t len;
+ pid_t child;
+ char fileNum[16];
+ UInt8 *buff;
+ const char *args[] = { kToolPath, NULL, "A", NULL, NULL };
+ AuthorizationExternalForm authExt;
+
+ err = ExternalizeAuthority(&authExt);
+ require_noerr(err, AuthFailed);
+
+ dataLen = CFDataGetLength(paramData);
+ buff = (UInt8*) malloc(dataLen * sizeof(UInt8));
+ require_action(buff != NULL, AllocBuffFailed, err=memFullErr;);
+ {
+ CFRange all = { 0, dataLen };
+ CFDataGetBytes(paramData, all, buff);
+ }
+
+ commFD = fileno(tmpfile());
+ sprintf(fileNum, "%d", commFD);
+ args[1] = fileNum;
+ args[3] = subCmd;
+
+ // write authority to pipe
+ len = 0; // tag, unused
+ write(commFD, &len, sizeof len);
+ len = sizeof authExt; // len
+ write(commFD, &len, sizeof len);
+ write(commFD, &authExt, len);
+
+ // write parameter to pipe
+ len = 0; // tag, unused
+ write(commFD, &len, sizeof len);
+ len = dataLen; // len
+ write(commFD, &len, sizeof len);
+ write(commFD, buff, len);
+
+ child = execTool(args);
+ if (child > 0) {
+ int status;
+ waitpid(child, &status, 0);
+ if (WIFEXITED(status))
+ err = WEXITSTATUS(status);
+ //fprintf(stderr, "child exited; status = %d (%ld)\n", status, err);
+ }
+
+ close(commFD);
+
+ free(buff);
+AllocBuffFailed:
+AuthFailed:
+ return err;
+}
+
+OSStatus
+WriteBrowseDomain(CFDataRef domainArrayData)
+{
+ if (!CurrentlyAuthorized())
+ return authFailErr;
+ return ExecWithCmdAndParam("Wb", domainArrayData);
+}
+
+OSStatus
+WriteRegistrationDomain(CFDataRef domainArrayData)
+{
+ if (!CurrentlyAuthorized())
+ return authFailErr;
+ return ExecWithCmdAndParam("Wd", domainArrayData);
+}
+
+OSStatus
+WriteHostname(CFDataRef domainArrayData)
+{
+ if (!CurrentlyAuthorized())
+ return authFailErr;
+ return ExecWithCmdAndParam("Wh", domainArrayData);
+}
+
+OSStatus
+SetKeyForDomain(CFDataRef secretData)
+{
+ if (!CurrentlyAuthorized())
+ return authFailErr;
+ return ExecWithCmdAndParam("Wk", secretData);
+}
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/PrivilegedOperations.h b/mDNSResponder/mDNSMacOSX/PreferencePane/PrivilegedOperations.h
new file mode 100644
index 00000000..91a60daf
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/PrivilegedOperations.h
@@ -0,0 +1,70 @@
+/*
+ File: PrivilegedOperations.h
+
+ Abstract: Interface to "ddnswriteconfig" setuid root tool.
+
+ Copyright: (c) Copyright 2005 Apple Computer, Inc. All rights reserved.
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
+ ("Apple") in consideration of your agreement to the following terms, and your
+ use, installation, modification or redistribution of this Apple software
+ constitutes acceptance of these terms. If you do not agree with these terms,
+ please do not use, install, modify or redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject
+ to these terms, Apple grants you a personal, non-exclusive license, under Apple's
+ copyrights in this original Apple software (the "Apple Software"), to use,
+ reproduce, modify and redistribute the Apple Software, with or without
+ modifications, in source and/or binary forms; provided that if you redistribute
+ the Apple Software in its entirety and without modifications, you must retain
+ this notice and the following text and disclaimers in all such redistributions of
+ the Apple Software. Neither the name, trademarks, service marks or logos of
+ Apple Computer, Inc. may be used to endorse or promote products derived from the
+ Apple Software without specific prior written permission from Apple. Except as
+ expressly stated in this notice, no other rights or licenses, express or implied,
+ are granted by Apple herein, including but not limited to any patent rights that
+ may be infringed by your derivative works or by other works in which the Apple
+ Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <CoreServices/CoreServices.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+#define PRIV_OP_TOOL_VERS 4
+
+#define kToolName "ddnswriteconfig"
+#define kToolPath "/Library/Application Support/Bonjour/" kToolName
+#define kToolInstaller "installtool"
+
+#define SC_DYNDNS_SETUP_KEY CFSTR("Setup:/Network/DynamicDNS")
+#define SC_DYNDNS_STATE_KEY CFSTR("State:/Network/DynamicDNS")
+#define SC_DYNDNS_REGDOMAINS_KEY CFSTR("RegistrationDomains")
+#define SC_DYNDNS_BROWSEDOMAINS_KEY CFSTR("BrowseDomains")
+#define SC_DYNDNS_HOSTNAMES_KEY CFSTR("HostNames")
+#define SC_DYNDNS_DOMAIN_KEY CFSTR("Domain")
+#define SC_DYNDNS_KEYNAME_KEY CFSTR("KeyName")
+#define SC_DYNDNS_SECRET_KEY CFSTR("Secret")
+#define SC_DYNDNS_ENABLED_KEY CFSTR("Enabled")
+#define SC_DYNDNS_STATUS_KEY CFSTR("Status")
+#define DYNDNS_KEYCHAIN_DESCRIPTION "Dynamic DNS Key"
+
+
+OSStatus EnsureToolInstalled(void);
+OSStatus WriteRegistrationDomain(CFDataRef domainArrayData);
+OSStatus WriteBrowseDomain(CFDataRef domainArrayData);
+OSStatus WriteHostname(CFDataRef domainArrayData);
+OSStatus SetKeyForDomain(CFDataRef secretData);
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/ddnswriteconfig.m b/mDNSResponder/mDNSMacOSX/PreferencePane/ddnswriteconfig.m
new file mode 100644
index 00000000..437879bc
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/ddnswriteconfig.m
@@ -0,0 +1,442 @@
+/*
+ File: ddnswriteconfig.m
+
+ Abstract: Setuid root tool invoked by Preference Pane to perform
+ privileged accesses to system configuration preferences and the system keychain.
+ Invoked by PrivilegedOperations.c.
+
+ Copyright: (c) Copyright 2005 Apple Computer, Inc. All rights reserved.
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
+ ("Apple") in consideration of your agreement to the following terms, and your
+ use, installation, modification or redistribution of this Apple software
+ constitutes acceptance of these terms. If you do not agree with these terms,
+ please do not use, install, modify or redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject
+ to these terms, Apple grants you a personal, non-exclusive license, under Apple's
+ copyrights in this original Apple software (the "Apple Software"), to use,
+ reproduce, modify and redistribute the Apple Software, with or without
+ modifications, in source and/or binary forms; provided that if you redistribute
+ the Apple Software in its entirety and without modifications, you must retain
+ this notice and the following text and disclaimers in all such redistributions of
+ the Apple Software. Neither the name, trademarks, service marks or logos of
+ Apple Computer, Inc. may be used to endorse or promote products derived from the
+ Apple Software without specific prior written permission from Apple. Except as
+ expressly stated in this notice, no other rights or licenses, express or implied,
+ are granted by Apple herein, including but not limited to any patent rights that
+ may be infringed by your derivative works or by other works in which the Apple
+ Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#import "PrivilegedOperations.h"
+#import "ConfigurationRights.h"
+
+#import <stdio.h>
+#import <stdint.h>
+#import <stdlib.h>
+#import <unistd.h>
+#import <fcntl.h>
+#import <errno.h>
+#import <sys/types.h>
+#import <sys/stat.h>
+#import <sys/mman.h>
+#import <mach-o/dyld.h>
+#import <dns_sd.h>
+#import <AssertMacros.h>
+#import <Security/Security.h>
+#import <CoreServices/CoreServices.h>
+#import <CoreFoundation/CoreFoundation.h>
+#import <SystemConfiguration/SystemConfiguration.h>
+#import <Foundation/Foundation.h>
+
+
+static AuthorizationRef gAuthRef = 0;
+
+static OSStatus
+WriteArrayToDynDNS(CFStringRef arrayKey, CFArrayRef domainArray)
+{
+ SCPreferencesRef store;
+ OSStatus err = noErr;
+ CFDictionaryRef origDict;
+ CFMutableDictionaryRef dict = NULL;
+ Boolean result;
+ CFStringRef scKey = CFSTR("/System/Network/DynamicDNS");
+
+
+ // Add domain to the array member ("arrayKey") of the DynamicDNS dictionary
+ // Will replace duplicate, at head of list
+ // At this point, we only support a single-item list
+ store = SCPreferencesCreate(NULL, CFSTR("com.apple.preference.bonjour"), NULL);
+ require_action(store != NULL, SysConfigErr, err=paramErr;);
+ require_action(true == SCPreferencesLock( store, true), LockFailed, err=coreFoundationUnknownErr;);
+
+ origDict = SCPreferencesPathGetValue(store, scKey);
+ if (origDict) {
+ dict = CFDictionaryCreateMutableCopy(NULL, 0, origDict);
+ }
+
+ if (!dict) {
+ dict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ }
+ require_action( dict != NULL, NoDict, err=memFullErr;);
+
+ if (CFArrayGetCount(domainArray) > 0) {
+ CFDictionarySetValue(dict, arrayKey, domainArray);
+ } else {
+ CFDictionaryRemoveValue(dict, arrayKey);
+ }
+
+ result = SCPreferencesPathSetValue(store, scKey, dict);
+ require_action(result, SCError, err=kernelPrivilegeErr;);
+
+ result = SCPreferencesCommitChanges(store);
+ require_action(result, SCError, err=kernelPrivilegeErr;);
+ result = SCPreferencesApplyChanges(store);
+ require_action(result, SCError, err=kernelPrivilegeErr;);
+
+SCError:
+ CFRelease(dict);
+NoDict:
+ SCPreferencesUnlock(store);
+LockFailed:
+ CFRelease(store);
+SysConfigErr:
+ return err;
+}
+
+
+static int
+readTaggedBlock(int fd, u_int32_t *pTag, u_int32_t *pLen, char **ppBuff)
+// Read tag, block len and block data from stream and return. Dealloc *ppBuff via free().
+{
+ ssize_t num;
+ u_int32_t tag, len; // Don't use ssize_t because that's different on 32- vs. 64-bit
+ int result = 0;
+
+ num = read(fd, &tag, sizeof tag);
+ require_action(num == sizeof tag, GetTagFailed, result = -1;);
+ num = read(fd, &len, sizeof len);
+ require_action(num == sizeof len, GetLenFailed, result = -1;);
+
+ *ppBuff = (char*) malloc( len);
+ require_action(*ppBuff != NULL, AllocFailed, result = -1;);
+
+ num = read(fd, *ppBuff, len);
+ if (num == (ssize_t)len) {
+ *pTag = tag;
+ *pLen = len;
+ } else {
+ free(*ppBuff);
+ result = -1;
+ }
+
+AllocFailed:
+GetLenFailed:
+GetTagFailed:
+ return result;
+}
+
+
+
+static int
+SetAuthInfo( int fd)
+{
+ int result = 0;
+ u_int32_t tag, len;
+ char *p;
+
+ result = readTaggedBlock( fd, &tag, &len, &p);
+ require( result == 0, ReadParamsFailed);
+ require( len == sizeof(AuthorizationExternalForm), ReadParamsFailed);
+ require( len == kAuthorizationExternalFormLength, ReadParamsFailed);
+
+ if (gAuthRef != 0) {
+ (void) AuthorizationFree(gAuthRef, kAuthorizationFlagDefaults);
+ gAuthRef = 0;
+ }
+
+ result = AuthorizationCreateFromExternalForm((AuthorizationExternalForm*) p, &gAuthRef);
+
+ free( p);
+ReadParamsFailed:
+ return result;
+}
+
+
+static int
+HandleWriteDomain(int fd, int domainType)
+{
+ CFArrayRef domainArray;
+ CFDataRef domainData;
+ int result = 0;
+ u_int32_t tag, len;
+ char *p;
+
+ AuthorizationItem scAuth = { UPDATE_SC_RIGHT, 0, NULL, 0 };
+ AuthorizationRights authSet = { 1, &scAuth };
+
+ if (noErr != (result = AuthorizationCopyRights(gAuthRef, &authSet, NULL, (AuthorizationFlags)0, NULL)))
+ return result;
+
+ result = readTaggedBlock(fd, &tag, &len, &p);
+ require(result == 0, ReadParamsFailed);
+
+ domainData = CFDataCreate(NULL, (UInt8 *)p, len);
+ domainArray = (CFArrayRef)[NSUnarchiver unarchiveObjectWithData:(NSData *)domainData];
+
+ if (domainType) {
+ result = WriteArrayToDynDNS(SC_DYNDNS_REGDOMAINS_KEY, domainArray);
+ } else {
+ result = WriteArrayToDynDNS(SC_DYNDNS_BROWSEDOMAINS_KEY, domainArray);
+ }
+
+ReadParamsFailed:
+ return result;
+}
+
+
+static int
+HandleWriteHostname(int fd)
+{
+ CFArrayRef domainArray;
+ CFDataRef domainData;
+ int result = 0;
+ u_int32_t tag, len;
+ char *p;
+
+ AuthorizationItem scAuth = { UPDATE_SC_RIGHT, 0, NULL, 0 };
+ AuthorizationRights authSet = { 1, &scAuth };
+
+ if (noErr != (result = AuthorizationCopyRights(gAuthRef, &authSet, NULL, (AuthorizationFlags) 0, NULL)))
+ return result;
+
+ result = readTaggedBlock(fd, &tag, &len, &p);
+ require(result == 0, ReadParamsFailed);
+
+ domainData = CFDataCreate(NULL, (const UInt8 *)p, len);
+ domainArray = (CFArrayRef)[NSUnarchiver unarchiveObjectWithData:(NSData *)domainData];
+ result = WriteArrayToDynDNS(SC_DYNDNS_HOSTNAMES_KEY, domainArray);
+
+ReadParamsFailed:
+ return result;
+}
+
+
+static SecAccessRef
+MyMakeUidAccess(uid_t uid)
+{
+ // make the "uid/gid" ACL subject
+ // this is a CSSM_LIST_ELEMENT chain
+ CSSM_ACL_PROCESS_SUBJECT_SELECTOR selector = {
+ CSSM_ACL_PROCESS_SELECTOR_CURRENT_VERSION, // selector version
+ CSSM_ACL_MATCH_UID, // set mask: match uids (only)
+ uid, // uid to match
+ 0 // gid (not matched here)
+ };
+ CSSM_LIST_ELEMENT subject2 = { NULL, 0, 0, {{0,0,0}} };
+ subject2.Element.Word.Data = (UInt8 *)&selector;
+ subject2.Element.Word.Length = sizeof(selector);
+ CSSM_LIST_ELEMENT subject1 = { &subject2, CSSM_ACL_SUBJECT_TYPE_PROCESS, CSSM_LIST_ELEMENT_WORDID, {{0,0,0}} };
+
+
+ // rights granted (replace with individual list if desired)
+ CSSM_ACL_AUTHORIZATION_TAG rights[] = {
+ CSSM_ACL_AUTHORIZATION_ANY // everything
+ };
+ // owner component (right to change ACL)
+ CSSM_ACL_OWNER_PROTOTYPE owner = {
+ // TypedSubject
+ { CSSM_LIST_TYPE_UNKNOWN, &subject1, &subject2 },
+ // Delegate
+ false
+ };
+ // ACL entries (any number, just one here)
+ CSSM_ACL_ENTRY_INFO acls =
+ {
+ // CSSM_ACL_ENTRY_PROTOTYPE
+ {
+ { CSSM_LIST_TYPE_UNKNOWN, &subject1, &subject2 }, // TypedSubject
+ false, // Delegate
+ { sizeof(rights) / sizeof(rights[0]), rights }, // Authorization rights for this entry
+ { { 0, 0 }, { 0, 0 } }, // CSSM_ACL_VALIDITY_PERIOD
+ "" // CSSM_STRING EntryTag
+ },
+ // CSSM_ACL_HANDLE
+ 0
+ };
+
+ SecAccessRef a = NULL;
+ (void) SecAccessCreateFromOwnerAndACL(&owner, 1, &acls, &a);
+ return a;
+}
+
+
+static OSStatus
+MyAddDynamicDNSPassword(SecKeychainRef keychain, SecAccessRef a, UInt32 serviceNameLength, const char *serviceName,
+ UInt32 accountNameLength, const char *accountName, UInt32 passwordLength, const void *passwordData)
+{
+ char * description = DYNDNS_KEYCHAIN_DESCRIPTION;
+ UInt32 descriptionLength = strlen(DYNDNS_KEYCHAIN_DESCRIPTION);
+ UInt32 type = 'ddns';
+ UInt32 creator = 'ddns';
+ UInt32 typeLength = sizeof(type);
+ UInt32 creatorLength = sizeof(creator);
+ OSStatus err;
+
+ // set up attribute vector (each attribute consists of {tag, length, pointer})
+ SecKeychainAttribute attrs[] = { { kSecLabelItemAttr, serviceNameLength, (char *)serviceName },
+ { kSecAccountItemAttr, accountNameLength, (char *)accountName },
+ { kSecServiceItemAttr, serviceNameLength, (char *)serviceName },
+ { kSecDescriptionItemAttr, descriptionLength, (char *)description },
+ { kSecTypeItemAttr, typeLength, (UInt32 *)&type },
+ { kSecCreatorItemAttr, creatorLength, (UInt32 *)&creator } };
+ SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs };
+
+ err = SecKeychainItemCreateFromContent(kSecGenericPasswordItemClass, &attributes, passwordLength, passwordData, keychain, a, NULL);
+ return err;
+}
+
+
+static int
+SetKeychainEntry(int fd)
+// Create a new entry in system keychain, or replace existing
+{
+ CFDataRef secretData;
+ CFDictionaryRef secretDictionary;
+ CFStringRef keyNameString;
+ CFStringRef domainString;
+ CFStringRef secretString;
+ SecKeychainItemRef item = NULL;
+ int result = 0;
+ u_int32_t tag, len;
+ char *p;
+ char keyname[kDNSServiceMaxDomainName];
+ char domain[kDNSServiceMaxDomainName];
+ char secret[kDNSServiceMaxDomainName];
+
+ AuthorizationItem kcAuth = { EDIT_SYS_KEYCHAIN_RIGHT, 0, NULL, 0 };
+ AuthorizationRights authSet = { 1, &kcAuth };
+
+ if (noErr != (result = AuthorizationCopyRights(gAuthRef, &authSet, NULL, (AuthorizationFlags)0, NULL)))
+ return result;
+
+ result = readTaggedBlock(fd, &tag, &len, &p);
+ require_noerr(result, ReadParamsFailed);
+
+ secretData = CFDataCreate(NULL, (UInt8 *)p, len);
+ secretDictionary = (CFDictionaryRef)[NSUnarchiver unarchiveObjectWithData:(NSData *)secretData];
+
+ keyNameString = (CFStringRef)CFDictionaryGetValue(secretDictionary, SC_DYNDNS_KEYNAME_KEY);
+ assert(keyNameString != NULL);
+
+ domainString = (CFStringRef)CFDictionaryGetValue(secretDictionary, SC_DYNDNS_DOMAIN_KEY);
+ assert(domainString != NULL);
+
+ secretString = (CFStringRef)CFDictionaryGetValue(secretDictionary, SC_DYNDNS_SECRET_KEY);
+ assert(secretString != NULL);
+
+ CFStringGetCString(keyNameString, keyname, kDNSServiceMaxDomainName, kCFStringEncodingUTF8);
+ CFStringGetCString(domainString, domain, kDNSServiceMaxDomainName, kCFStringEncodingUTF8);
+ CFStringGetCString(secretString, secret, kDNSServiceMaxDomainName, kCFStringEncodingUTF8);
+
+ result = SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
+ if (result == noErr) {
+ result = SecKeychainFindGenericPassword(NULL, strlen(domain), domain, 0, NULL, 0, NULL, &item);
+ if (result == noErr) {
+ result = SecKeychainItemDelete(item);
+ if (result != noErr) fprintf(stderr, "SecKeychainItemDelete returned %d\n", result);
+ }
+
+ result = MyAddDynamicDNSPassword(NULL, MyMakeUidAccess(0), strlen(domain), domain, strlen(keyname)+1, keyname, strlen(secret)+1, secret);
+ if (result != noErr) fprintf(stderr, "MyAddDynamicDNSPassword returned %d\n", result);
+ if (item) CFRelease(item);
+ }
+
+ReadParamsFailed:
+ return result;
+}
+
+
+int main( int argc, char **argv)
+/* argv[0] is the exec path; argv[1] is a fd for input data; argv[2]... are operation codes.
+ The tool supports the following operations:
+ V -- exit with status PRIV_OP_TOOL_VERS
+ A -- read AuthInfo from input pipe
+ Wd -- write registration domain to dynamic store
+ Wb -- write browse domain to dynamic store
+ Wh -- write hostname to dynamic store
+ Wk -- write keychain entry for given account name
+*/
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ int commFD = -1, iArg, result = 0;
+
+ if ( 0 != seteuid( 0))
+ return -1;
+
+ if ( argc == 3 && 0 == strcmp( argv[2], "V"))
+ return PRIV_OP_TOOL_VERS;
+
+ if ( argc > 1)
+ {
+ commFD = strtol( argv[1], NULL, 0);
+ lseek( commFD, 0, SEEK_SET);
+ }
+ for ( iArg = 2; iArg < argc && result == 0; iArg++)
+ {
+ if ( 0 == strcmp( "A", argv[ iArg])) // get auth info
+ {
+ result = SetAuthInfo( commFD);
+ }
+ else if ( 0 == strcmp( "Wd", argv[ iArg])) // Write registration domain
+ {
+ result = HandleWriteDomain( commFD, 1);
+ }
+ else if ( 0 == strcmp( "Wb", argv[ iArg])) // Write browse domain
+ {
+ result = HandleWriteDomain( commFD, 0);
+ }
+ else if ( 0 == strcmp( "Wh", argv[ iArg])) // Write hostname
+ {
+ result = HandleWriteHostname( commFD);
+ }
+ else if ( 0 == strcmp( "Wk", argv[ iArg])) // Write keychain entry
+ {
+ result = SetKeychainEntry( commFD);
+ }
+ }
+ [pool release];
+ return result;
+}
+
+// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
+// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
+// To expand "version" to its value before making the string, use STRINGIFY(version) instead
+#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
+#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
+
+// NOT static -- otherwise the compiler may optimize it out
+// The "@(#) " pattern is a special prefix the "what" command looks for
+const char VersionString_SCCS[] = "@(#) ddnswriteconfig " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
+
+#if _BUILDING_XCODE_PROJECT_
+// If the process crashes, then this string will be magically included in the automatically-generated crash log
+const char *__crashreporter_info__ = VersionString_SCCS + 5;
+asm(".desc ___crashreporter_info__, 0x10");
+#endif
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/installtool b/mDNSResponder/mDNSMacOSX/PreferencePane/installtool
new file mode 100755
index 00000000..ce341c87
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/installtool
@@ -0,0 +1,94 @@
+#!/usr/bin/perl
+# Emacs settings: -*- tab-width: 4 -*-
+#
+# File: installtool
+#
+# Abstract: Copy "ddnswriteconfig" to Application Support and make it setuid root.
+#
+# Copyright: (c) Copyright 2005 Apple Computer, Inc. All rights reserved.
+#
+# Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
+# ("Apple") in consideration of your agreement to the following terms, and your
+# use, installation, modification or redistribution of this Apple software
+# constitutes acceptance of these terms. If you do not agree with these terms,
+# please do not use, install, modify or redistribute this Apple software.
+#
+# In consideration of your agreement to abide by the following terms, and subject
+# to these terms, Apple grants you a personal, non-exclusive license, under Apple's
+# copyrights in this original Apple software (the "Apple Software"), to use,
+# reproduce, modify and redistribute the Apple Software, with or without
+# modifications, in source and/or binary forms; provided that if you redistribute
+# the Apple Software in its entirety and without modifications, you must retain
+# this notice and the following text and disclaimers in all such redistributions of
+# the Apple Software. Neither the name, trademarks, service marks or logos of
+# Apple Computer, Inc. may be used to endorse or promote products derived from the
+# Apple Software without specific prior written permission from Apple. Except as
+# expressly stated in this notice, no other rights or licenses, express or implied,
+# are granted by Apple herein, including but not limited to any patent rights that
+# may be infringed by your derivative works or by other works in which the Apple
+# Software may be incorporated.
+#
+# The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
+# WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+# WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+# COMBINATION WITH YOUR PRODUCTS.
+#
+# IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+# OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+# (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Create the Bonjour subdirectory.
+# Copy ARGV[0] to $dest and set owner and suid permissions.
+#
+# This script will be run as root by the AEWP trampoline.
+#
+
+use File::Temp qw/ :mktemp /;
+
+$dest_dir = "/Library/Application Support/Bonjour";
+$dest = $dest_dir . "/ddnswriteconfig";
+
+$template = ".XXXXXX";
+
+# Perl seems to think this code is running setuid root, so it applies its security checks.
+# See <http://www.monster-submit.com/resources/docs/pod/perlsec.html>.
+# In fact this is NOT a setuid script. It is a normal unprivileged user-level script --
+# but it is run as root when properly authorized by a user with an admin password,
+# via the AuthorizationExecuteWithPrivileges() call.
+# We therefore have to do this trick pattern match to 'untaint' the source file specified in $ARGV[0].
+if ($ARGV[0] =~ /^(.+)$/) { $src = $1; }
+
+# Also clear $ENV{PATH} so we don't get "Insecure $ENV{PATH}" fatal errors
+$ENV{PATH} = "";
+
+if (! -d $dest_dir) {
+ $dest_tmp_dir = mkdtemp ($dest_dir . $template);
+ (chown 0, 80, $dest_tmp_dir) or cleanup_dir();
+ (chmod 0755, $dest_tmp_dir) or cleanup_dir();
+ (rename $dest_tmp_dir, $dest_dir) or cleanup_dir();
+}
+
+$dest_tmp = mktemp ($dest . $template);
+
+if ($src ne '') {
+ system ('/bin/cp', '-f', $src, $dest_tmp) and cleanup();
+ (chown 0, 80, $dest_tmp) or cleanup();
+ (chmod 04555, $dest_tmp) or cleanup();
+ (rename $dest_tmp, $dest) or cleanup();
+}
+exit (0);
+
+sub cleanup {
+ unlink $dest_tmp;
+ exit (1);
+}
+
+sub cleanup_dir {
+ unlink $dest_tmp_dir;
+ exit (1);
+}