diff options
Diffstat (limited to 'mDNSResponder/mDNSMacOSX/PreferencePane')
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 Binary files differnew file mode 100644 index 00000000..b78b0c2a --- /dev/null +++ b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/add_idle.tiff diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/add_pressed.tiff b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/add_pressed.tiff Binary files differnew file mode 100644 index 00000000..b842e20c --- /dev/null +++ b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/add_pressed.tiff diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/failure.tiff b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/failure.tiff Binary files differnew file mode 100644 index 00000000..89a10dfe --- /dev/null +++ b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/failure.tiff diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/inprogress.tiff b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/inprogress.tiff Binary files differnew file mode 100644 index 00000000..340bb335 --- /dev/null +++ b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/inprogress.tiff diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_disabled.tiff b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_disabled.tiff Binary files differnew file mode 100644 index 00000000..70d3dd9c --- /dev/null +++ b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_disabled.tiff diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_idle.tiff b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_idle.tiff Binary files differnew file mode 100644 index 00000000..dacc97c3 --- /dev/null +++ b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_idle.tiff diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_pressed.tiff b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_pressed.tiff Binary files differnew file mode 100644 index 00000000..de3f8779 --- /dev/null +++ b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_pressed.tiff diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/success.tiff b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/success.tiff Binary files differnew file mode 100644 index 00000000..21702a9a --- /dev/null +++ b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/success.tiff diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPref.icns b/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPref.icns Binary files differnew file mode 100644 index 00000000..5ba4674e --- /dev/null +++ b/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPref.icns diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPref.tiff b/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPref.tiff Binary files differnew file mode 100644 index 00000000..55cb212c --- /dev/null +++ b/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPref.tiff 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(®Query.service, flags, 0, registrationDomainReply, (void *)self); + if (err == kDNSServiceErr_NoError) MyDNSServiceAddServiceToRunLoop(®Query); + + 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 Binary files differnew file mode 100644 index 00000000..eec01ee4 --- /dev/null +++ b/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib/keyedobjects.nib diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/InfoPlist.strings b/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/InfoPlist.strings Binary files differnew file mode 100644 index 00000000..e2dfa991 --- /dev/null +++ b/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/InfoPlist.strings 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); +} |