/* * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ /*! * @header CConfigs * Code to parse a XML config file. */ #include "CConfigs.h" #include "CLog.h" #include #include //used for strcpy, etc. #include //used for malloc #include //used for mkdir and stat #include "PrivateTypes.h" #include "DSUtils.h" // -------------------------------------------------------------------------------- // * CConfigs // -------------------------------------------------------------------------------- CConfigs::CConfigs ( void ) { fSearchPolicy = kNetInfoSearchPolicy; fSearchNodeListLength = 0; pSearchNodeList = nil; fDirRef = 0; fConfigDict = nil; fSearchNodeConfigFileName = nil; fSearchNodeConfigBackupFileName = nil; fSearchNodeConfigCorruptedFileName = nil; fXMLSearchPathVersionKeyString = CFStringCreateWithCString( NULL, kXMLSearchPathVersionKey, kCFStringEncodingUTF8 ); fXMLSearchPolicyKeyString = CFStringCreateWithCString( NULL, kXMLSearchPolicyKey, kCFStringEncodingUTF8 ); fXMLSearchPathArrayKeyString = CFStringCreateWithCString( NULL, kXMLSearchPathArrayKey, kCFStringEncodingUTF8 ); fXMLSearchDHCPLDAPString = CFStringCreateWithCString( NULL, kXMLSearchDHCPLDAP, kCFStringEncodingUTF8 ); } // CConfigs // -------------------------------------------------------------------------------- // * ~CConfigs () // -------------------------------------------------------------------------------- CConfigs::~CConfigs ( void ) { //need to cleanup the struct list ie. the internals //NO NO these are created on demand and owned by the caller to GetCustom //KW should use local vars for this purpose // pList = pSearchNodeList; // while (pList != nil) // { // pDeleteList = pList; // pList = pList->fNext; //assign to next BEFORE deleting current // CleanListData( pDeleteList ); // delete( pDeleteList ); // pDeleteList = nil; // } //KW might consider cleanup of the fDirRef here if (fConfigDict) { CFRelease(fConfigDict); } if (fSearchNodeConfigFileName != nil) { free(fSearchNodeConfigFileName); fSearchNodeConfigFileName = nil; } if (fSearchNodeConfigBackupFileName != nil) { free(fSearchNodeConfigBackupFileName); fSearchNodeConfigBackupFileName = nil; } if (fSearchNodeConfigCorruptedFileName != nil) { free(fSearchNodeConfigCorruptedFileName); fSearchNodeConfigCorruptedFileName = nil; } CFRelease(fXMLSearchPathVersionKeyString); CFRelease(fXMLSearchPolicyKeyString); CFRelease(fXMLSearchPathArrayKeyString); CFRelease(fXMLSearchDHCPLDAPString); } // ~CConfigs // -------------------------------------------------------------------------------- // * Init (uInt32) // -------------------------------------------------------------------------------- sInt32 CConfigs::Init ( const char *inSearchNodeConfigFilePrefix, uInt32 &outSearchPolicy ) { sInt32 siResult = eDSNullParameter; CFMutableArrayRef cfArrayRef = NULL; CFIndex cfConfigCount = 0; CFMutableStringRef cfSearchNode = NULL; CFRange cfRangeVal; struct stat statResult; bool bUpdateConfig = false; CFStringRef cfStringRef = NULL; try { if (inSearchNodeConfigFilePrefix != nil) { fSearchNodeConfigFileName = (char *) ::calloc(::strlen(inSearchNodeConfigFilePrefix) + ::strlen(".plist") + 1 , sizeof(char) ); ::strcpy(fSearchNodeConfigFileName, inSearchNodeConfigFilePrefix); ::strcat(fSearchNodeConfigFileName, ".plist"); fSearchNodeConfigBackupFileName = (char *) ::calloc(::strlen(inSearchNodeConfigFilePrefix) + ::strlen("Backup.plist") + 1 , sizeof(char) ); ::strcpy(fSearchNodeConfigBackupFileName, inSearchNodeConfigFilePrefix); ::strcat(fSearchNodeConfigBackupFileName, "Backup.plist"); fSearchNodeConfigCorruptedFileName = (char *) ::calloc(::strlen(inSearchNodeConfigFilePrefix) + ::strlen("Corrupted.plist") + 1 , sizeof(char) ); ::strcpy(fSearchNodeConfigCorruptedFileName, inSearchNodeConfigFilePrefix); ::strcat(fSearchNodeConfigCorruptedFileName, "Corrupted.plist"); siResult = eDSNoErr; //get the search policy siResult = ConfigSearchPolicy(); if (siResult == eDSNoErr) //which it should always be { outSearchPolicy = fSearchPolicy; } //let's see if we need to convert any deprecated node names //ie. LDAPv2 to LDAPv3 //ie. BSD Configuration Files to BSD //only do this if the deprecated plugins are not present cfArrayRef = nil; if ( CFDictionaryContainsKey( fConfigDict, fXMLSearchPathArrayKeyString ) ) { cfArrayRef = (CFMutableArrayRef)CFDictionaryGetValue( fConfigDict, fXMLSearchPathArrayKeyString ); } if (cfArrayRef != nil) { CFStringRef cfLDAPv2Prefix = CFStringCreateWithCString( NULL, "/LDAPv2/", kCFStringEncodingUTF8 ); CFStringRef cfLDAPv3Prefix = CFStringCreateWithCString( NULL, "/LDAPv3/", kCFStringEncodingUTF8 ); CFStringRef cfBSDOldPrefix = CFStringCreateWithCString( NULL, "/BSD Configuration Files/Local", kCFStringEncodingUTF8 ); CFStringRef cfBSDNewPrefix = CFStringCreateWithCString( NULL, "/BSD/local", kCFStringEncodingUTF8 ); cfConfigCount = ::CFArrayGetCount( cfArrayRef ); for (sInt32 iConfigIndex = 0; iConfigIndex < cfConfigCount; iConfigIndex++) { cfSearchNode = (CFMutableStringRef)::CFArrayGetValueAtIndex( cfArrayRef, iConfigIndex ); if ( cfSearchNode != nil ) { if ( CFGetTypeID( cfSearchNode ) == CFStringGetTypeID() ) { cfRangeVal = CFStringFind(cfSearchNode, cfLDAPv2Prefix, NULL); if (cfRangeVal.location == 0) { if (stat( "/System/Library/Frameworks/DirectoryService.framework/Resources/Plugins/LDAPv2.dsplug", &statResult ) != eDSNoErr) { cfSearchNode = CFStringCreateMutableCopy(NULL, 0, cfSearchNode); //replace LDAPv2 with LDAPv3 CFStringReplace(cfSearchNode, cfRangeVal, cfLDAPv3Prefix); CFArraySetValueAtIndex( cfArrayRef, iConfigIndex, cfSearchNode ); CFRelease(cfSearchNode); bUpdateConfig = true; } continue; } cfRangeVal = CFStringFind(cfSearchNode, cfBSDOldPrefix, NULL); if (cfRangeVal.location == 0) { if (stat( "/System/Library/Frameworks/DirectoryService.framework/Resources/Plugins/BSD Configuration Files.dsplug", &statResult ) != eDSNoErr) { cfSearchNode = CFStringCreateMutableCopy(NULL, 0, cfSearchNode); //replace BSD Configuration Files with BSD CFStringReplace(cfSearchNode, cfRangeVal, cfBSDNewPrefix); CFArraySetValueAtIndex( cfArrayRef, iConfigIndex, cfSearchNode ); CFRelease(cfSearchNode); bUpdateConfig = true; } continue; } } } } CFRelease(cfLDAPv2Prefix); cfLDAPv2Prefix = NULL; CFRelease(cfLDAPv3Prefix); cfLDAPv3Prefix = NULL; CFRelease(cfBSDOldPrefix); cfBSDOldPrefix = NULL; CFRelease(cfBSDNewPrefix); cfBSDNewPrefix = NULL; } if (bUpdateConfig) { cfStringRef = CFStringCreateWithCString( NULL, "Search Node PlugIn Version 1.6", kCFStringEncodingUTF8 ); CFDictionarySetValue( fConfigDict, fXMLSearchPathVersionKeyString, cfStringRef ); CFRelease(cfStringRef); WriteConfig(); } } } // try catch( sInt32 err ) { siResult = err; } return( siResult ); } // Init // -------------------------------------------------------------------------------- // * GetCustom (void) // -------------------------------------------------------------------------------- sSearchList *CConfigs:: GetCustom ( void ) { sSearchList *outList = nil; sInt32 siResult = eDSNoErr; //build the list and get the search policy //each time we call this we create a new one and assume that the old is owned by the previous caller pSearchNodeList = nil; siResult = ConfigList(); if (siResult == eDSNoErr) { outList = pSearchNodeList; } //no need to cleanup the struct list ie. the internals //since caller will handle it //nil is returned if there is a failure return( outList ); } // GetCustom // --------------------------------------------------------------------------- // * ConfigSearchPolicy // --------------------------------------------------------------------------- sInt32 CConfigs:: ConfigSearchPolicy ( void ) { sInt32 siResult = eDSNoErr; sInt32 result = eDSNoErr; CFStringRef errorString; CFURLRef configFileURL = nil; CFURLRef configFileCorruptedURL = nil; CFDataRef xmlData = nil; CFPropertyListRef configPropertyList = nil; CFMutableDictionaryRef configDict = nil; bool bFileOpSuccess = false; bool bWroteFile = false; bool bCorruptedFile = false; char string[ PATH_MAX ]; char *configVersion = nil; CFNumberRef aSearchPolicy; struct stat statResult; CFStringRef cfStringRef = nil; sInt32 errorCode = 0; int defaultSearchPolicy = 1; CFStringRef sBase = nil; CFStringRef sPath = nil; CFStringRef sCorruptedPath = nil; bool bUseXMLData = false; char *filenameString = nil; //Config data is read from a XML file OR created as default //KW eventually use Version from XML file to check against the code here? //Steps in the process: //1- see if the file exists //2- if it exists then try to read it otherwise just use created xmldata //3- if existing file is corrupted then rename it and save it while creating a new default file //4- if file doesn't exist then create a new default file - make sure directories exist/if not create them //make sure file permissions are root only //keep on going with a fConfigDict regardless whether file access works sPath = ::CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR( "/Library/Preferences/DirectoryService/%s" ), fSearchNodeConfigFileName ); ::memset(string,0,PATH_MAX); ::CFStringGetCString( sPath, string, sizeof( string ), kCFStringEncodingUTF8 ); DBGLOG( kLogPlugin, "Checking for Search Node XML config file:" ); DBGLOG1( kLogPlugin, "%s", string ); filenameString = strdup(string); // Convert it back into a CFURL. configFileURL = ::CFURLCreateWithFileSystemPath( kCFAllocatorDefault, sPath, kCFURLPOSIXPathStyle, false ); CFRelease( sPath ); // build with Create so okay to dealloac here sPath = nil; //step 1- see if the file exists //if not then make sure the directories exist or create them //then create a new file if necessary result = ::stat( string, &statResult ); //if file does not exist if (result != eDSNoErr) { //move down the path from the system defined local directory and check if it exists //if not create it sPath = ::CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR( "%@/%s" ), sBase, "/Preferences" ); ::memset(string,0,PATH_MAX); ::CFStringGetCString( sPath, string, sizeof( string ), kCFStringEncodingUTF8 ); result = ::stat( string, &statResult ); //if first sub directory does not exist if (result != eDSNoErr) { ::mkdir( string , 0775 ); ::chmod( string, 0775 ); //above 0775 doesn't seem to work - looks like umask modifies it } CFRelease( sPath ); // build with Create so okay to dealloac here sPath = nil; //next subdirectory sPath = ::CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR( "%@/%s" ), sBase, "/Preferences/DirectoryService" ); ::memset(string,0,PATH_MAX); ::CFStringGetCString( sPath, string, sizeof( string ), kCFStringEncodingUTF8 ); result = ::stat( string, &statResult ); //if second sub directory does not exist if (result != eDSNoErr) { ::mkdir( string , 0775 ); ::chmod( string, 0775 ); //above 0775 doesn't seem to work - looks like umask modifies it } CFRelease( sPath ); // build with Create so okay to dealloac here sPath = nil; //create a new dictionary for the file configDict = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); cfStringRef = CFSTR("Search Node PlugIn Version 1.6"); CFDictionarySetValue( configDict, fXMLSearchPathVersionKeyString, cfStringRef ); //CFRelease(cfStringRef); // we don't need to release CFSTR() created strings that we didn't retain aSearchPolicy = CFNumberCreate(NULL,kCFNumberIntType,&defaultSearchPolicy); CFDictionarySetValue( configDict, fXMLSearchPolicyKeyString, aSearchPolicy ); // default NetInfo search policy CFNumber if ( aSearchPolicy != nil ) { CFRelease( aSearchPolicy ); aSearchPolicy = nil; } //convert the dict into a XML blob xmlData = CFPropertyListCreateXMLData( kCFAllocatorDefault, configDict); bUseXMLData = true; //write the XML to the config file bFileOpSuccess = CFURLWriteDataAndPropertiesToResource( configFileURL, xmlData, NULL, &errorCode); ::chmod( filenameString, 0600 ); CFRelease(configDict); configDict = nil; //CFRelease(xmlData); //keeping this data for use below } // file does not exist so creating one else //try to read the existing file { // Read the XML property list file bFileOpSuccess = CFURLCreateDataAndPropertiesFromResource( kCFAllocatorDefault, configFileURL, &xmlData, // place to put file data NULL, NULL, &errorCode); if (!bFileOpSuccess) //if fails ensure xmlData ptr is nil { xmlData = nil; } else { bUseXMLData = true; } } if (xmlData != nil) { // extract the config dictionary from the XML data. configPropertyList = CFPropertyListCreateFromXMLData( kCFAllocatorDefault, xmlData, kCFPropertyListMutableContainers, //could also use kCFPropertyListImmutable, kCFPropertyListMutableContainers &errorString); if (configPropertyList != nil ) { DBGLOG( kLogPlugin, "Have read Search Node XML config file:" ); DBGLOG1( kLogPlugin, "%s", string ); //make the propertylist a dict if ( CFDictionaryGetTypeID() == CFGetTypeID( configPropertyList ) ) { configDict = (CFMutableDictionaryRef) configPropertyList; } if (configDict != nil) { //config file version configVersion = GetVersion(configDict); if (configVersion == nil ) //release the dict and assume corrupted file { CFRelease(configDict); configDict = nil; configPropertyList = nil; } else { fSearchPolicy = GetSearchPolicy(configDict); //set the member dict variable fConfigDict = configDict; free(configVersion); configVersion = nil; }//if (configVersion != nil) // don't release the configDict since it is the cast configPropertyList }//if (configDict != nil) }//if (configPropertyList != nil ) if ( configPropertyList == nil) //we have a corrupted file { DBGLOG( kLogPlugin, "Search Node XML config file is corrupted" ); DBGLOG( kLogPlugin, "Using default NetInfo Search Policy" ); bCorruptedFile = true; //here we need to make a backup of the file - why? - because // Append the subpath. sCorruptedPath = ::CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR( "%@/%s/%s" ), sBase, "/Preferences/DirectoryService", fSearchNodeConfigCorruptedFileName ); // Convert it into a CFURL. configFileCorruptedURL = ::CFURLCreateWithFileSystemPath( kCFAllocatorDefault, sCorruptedPath, kCFURLPOSIXPathStyle, false ); ::memset(string,0,PATH_MAX); ::CFStringGetCString( sCorruptedPath, string, sizeof( string ), kCFStringEncodingUTF8 ); CFRelease( sCorruptedPath ); // build with Create so okay to dealloac here sCorruptedPath = nil; //write the XML to the corrupted copy of the config file bWroteFile = CFURLWriteDataAndPropertiesToResource( configFileCorruptedURL, xmlData, NULL, &errorCode); ::chmod( string, 0600 ); } //couldn't extract the property list out of the file or the version didn't exist CFRelease(xmlData); // probably okay to dealloc since Create used and no longer needed xmlData = nil; } else { DBGLOG( kLogPlugin, "Search Node XML config file is not readable" ); DBGLOG( kLogPlugin, "Using default NetInfo Search Policy" ); bCorruptedFile = true; //here we make no backup since unable to read it at all } if (bCorruptedFile) { //here we create a whole new file //create a new dictionary for the file configDict = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); cfStringRef = CFSTR("Search Node PlugIn Version 1.6"); CFDictionarySetValue( configDict, fXMLSearchPathVersionKeyString, cfStringRef ); //CFRelease(cfStringRef); // don't release CFSTR() string if not retained aSearchPolicy = CFNumberCreate(NULL,kCFNumberIntType,&defaultSearchPolicy); CFDictionarySetValue( configDict, fXMLSearchPolicyKeyString, aSearchPolicy ); // default NetInfo search policy CFNumber if ( aSearchPolicy != nil ) { CFRelease( aSearchPolicy ); aSearchPolicy = nil; } //convert the dict into a XML blob xmlData = CFPropertyListCreateXMLData( kCFAllocatorDefault, configDict); CFRelease(configDict); if (sPath != nil) { CFRelease(sPath); } sPath = ::CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR( "/Library/Preferences/DirectoryService/%s" ), fSearchNodeConfigFileName ); if (configFileURL != nil) { CFRelease(configFileURL); } // Convert it back into a CFURL. configFileURL = ::CFURLCreateWithFileSystemPath( kCFAllocatorDefault, sPath, kCFURLPOSIXPathStyle, false ); ::memset(string,0,PATH_MAX); ::CFStringGetCString( sPath, string, sizeof( string ), kCFStringEncodingUTF8 ); //write the newly created XML to the config file bWroteFile = CFURLWriteDataAndPropertiesToResource( configFileURL, xmlData, NULL, &errorCode); ::chmod( string, 0600 ); if (xmlData != nil) { configPropertyList = CFPropertyListCreateFromXMLData( kCFAllocatorDefault, xmlData, kCFPropertyListMutableContainers, //could also use kCFPropertyListImmutable, kCFPropertyListMutableContainers &errorString); if ( configPropertyList != nil ) { DBGLOG( kLogPlugin, "Using Newly Replaced Search Node XML config file:" ); DBGLOG1( kLogPlugin, "%s", string ); //make the propertylist a dict if ( CFDictionaryGetTypeID() == CFGetTypeID( configPropertyList ) ) { configDict = (CFMutableDictionaryRef) configPropertyList; } if (configDict != nil) { //config file version configVersion = GetVersion(configDict); if (configVersion == nil ) //release the dict and assume corrupted file { CFRelease(configDict); configDict = nil; configPropertyList = nil; } else { fSearchPolicy = GetSearchPolicy(configDict); //set the member dict variable fConfigDict = configDict; free(configVersion); configVersion = nil; }//if (configVersion != nil) // don't release the configDict since it is the cast configPropertyList }//if (configDict != nil) }//if (configPropertyList != nil ) CFRelease(xmlData); xmlData = nil; } // if (xmlData != nil) } // if (bCorruptedFile) if (configFileURL != nil) { CFRelease(configFileURL); // seems okay to dealloc since Create used and done with it now configFileURL = nil; } if (configFileCorruptedURL != nil) { CFRelease(configFileCorruptedURL); // seems okay to dealloc since Create used and done with it now configFileCorruptedURL = nil; } if (sBase != nil) { CFRelease(sBase); // built with Copy so okay to dealloc sBase = nil; } if (sPath != nil) { CFRelease(sPath); sPath = nil; } if (filenameString != nil) { free(filenameString); filenameString = nil; } return( siResult ); } // ConfigSearchPolicy // --------------------------------------------------------------------------- // * WriteConfig // --------------------------------------------------------------------------- sInt32 CConfigs:: WriteConfig ( void ) { sInt32 siResult = eDSNoErr; CFURLRef configFileURL; CFURLRef configFileBackupURL; CFDataRef xmlData; bool bWroteFile = false; bool bReadFile = false; char string[ PATH_MAX ]; struct stat statResult; sInt32 errorCode = 0; char *filenameString = nil; //Config data is written to a XML file //Steps in the process: //1- see if the file exists //2- if it exists then overwrite it //KW 3- rename existing file and save it while creating a new file?? //4- if file doesn't exist then create a new default file - make sure directories exist/if not create them //make sure file permissions are root only CFStringRef sPath; sPath = ::CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR( "/Library/Preferences/DirectoryService/%s" ), fSearchNodeConfigFileName ); ::memset(string,0,PATH_MAX); ::CFStringGetCString( sPath, string, sizeof( string ), kCFStringEncodingUTF8 ); DBGLOG( kLogPlugin, "Checking for Search Node XML config file:" ); DBGLOG1( kLogPlugin, "%s", string ); filenameString = strdup(string); // Convert it back into a CFURL. configFileURL = ::CFURLCreateWithFileSystemPath( kCFAllocatorDefault, sPath, kCFURLPOSIXPathStyle, false ); CFRelease( sPath ); // build with Create so okay to dealloac here sPath = nil; //step 1- see if the file exists //if not then make sure the directories exist or create them //then write the file siResult = ::stat( string, &statResult ); //if file exists then we make a backup copy - why? - because if (siResult == eDSNoErr) { CFStringRef sBackupPath; sBackupPath = ::CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR( "/Library/Preferences/DirectoryService/%s" ), fSearchNodeConfigBackupFileName ); // Convert it into a CFURL. configFileBackupURL = ::CFURLCreateWithFileSystemPath( kCFAllocatorDefault, sBackupPath, kCFURLPOSIXPathStyle, false ); ::memset(string,0,PATH_MAX); ::CFStringGetCString( sBackupPath, string, sizeof( string ), kCFStringEncodingUTF8 ); CFRelease( sBackupPath ); // build with Create so okay to dealloac here sBackupPath = nil; // Read the old XML property list file bReadFile = CFURLCreateDataAndPropertiesFromResource( kCFAllocatorDefault, configFileURL, &xmlData, // place to put file data NULL, NULL, &siResult); //write the XML to the backup config file if (bReadFile) { bWroteFile = CFURLWriteDataAndPropertiesToResource( configFileBackupURL, xmlData, NULL, &errorCode); ::chmod( string, 0600 ); //KW check the error code and the result? CFRelease(xmlData); } if (configFileBackupURL != nil) { CFRelease(configFileBackupURL); configFileBackupURL = nil; } } //if file does not exist if (siResult != eDSNoErr) { siResult = eDSNoErr; //move down the path from the system defined local directory and check if it exists //if not create it sPath = ::CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR( "%s" ), "/Library/Preferences" ); ::memset(string,0,PATH_MAX); ::CFStringGetCString( sPath, string, sizeof( string ), kCFStringEncodingUTF8 ); siResult = ::stat( string, &statResult ); //if first sub directory does not exist if (siResult != eDSNoErr) { siResult = eDSNoErr; ::mkdir( string , 0775 ); ::chmod( string, 0775 ); //above 0775 doesn't seem to work - looks like umask modifies it } CFRelease( sPath ); // build with Create so okay to dealloac here sPath = nil; //next subdirectory sPath = ::CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR( "%s" ), "/Library/Preferences/DirectoryService" ); ::memset(string,0,PATH_MAX); ::CFStringGetCString( sPath, string, sizeof( string ), kCFStringEncodingUTF8 ); siResult = ::stat( string, &statResult ); //if second sub directory does not exist if (siResult != eDSNoErr) { siResult = eDSNoErr; ::mkdir( string , 0775 ); ::chmod( string, 0775 ); //above 0775 doesn't seem to work - looks like umask modifies it } CFRelease( sPath ); // build with Create so okay to dealloac here sPath = nil; } // file does not exist so checking directory path to enable write of a new file //now write the updated file if (fConfigDict) { //convert the dict into a XML blob xmlData = CFPropertyListCreateXMLData( kCFAllocatorDefault, fConfigDict); //write the XML to the config file bWroteFile = CFURLWriteDataAndPropertiesToResource( configFileURL, xmlData, NULL, &errorCode); ::chmod( filenameString, 0600 ); //KW check the error code and the result? CFRelease(xmlData); } if (configFileURL != nil) { CFRelease(configFileURL); // seems okay to dealloc since Create used and done with it now configFileURL = nil; } if (bWroteFile) { DBGLOG( kLogPlugin, "Have written the Search Node XML config file:" ); DBGLOG1( kLogPlugin, "%s", string ); siResult = eDSNoErr; } else { DBGLOG( kLogPlugin, "Search Node XML config file has NOT been written" ); DBGLOG( kLogPlugin, "Update to Custom Search Path Node List in Config File Failed" ); siResult = eDSPlugInConfigFileError; } if (filenameString != nil) { free(filenameString); filenameString = nil; } return( siResult ); } // WriteConfig // --------------------------------------------------------------------------- // * ConfigList // --------------------------------------------------------------------------- sInt32 CConfigs:: ConfigList ( void ) { sInt32 siResult = eDSNoErr; sSearchList *pSearchNode = nil; sSearchList *pTailSearchNode = nil; CFStringRef cfSearchNode; CFArrayRef cfArrayRef = nil; CFIndex cfConfigCount = 0; char *tmpBuff = nil; CFIndex cfBuffSize = 1024; char *outSearchNode = nil; try { //array of search nodes for search policy IF custom used //but retrieve anyways for possible future use cfArrayRef = nil; cfArrayRef = GetListArray(fConfigDict); if (cfArrayRef != nil) { //now we can retrieve each search node IN ORDER cfConfigCount = ::CFArrayGetCount( cfArrayRef ); //if (cfConfigCount == 0) //assume that this file has no Servers in it //and simply proceed forward ie. no Search Nodes will be obtained from data in this file //loop through the array //use iConfigIndex for the access to the cfArrayRef for (sInt32 iConfigIndex = 0; iConfigIndex < cfConfigCount; iConfigIndex++) { cfSearchNode = (CFStringRef)::CFArrayGetValueAtIndex( cfArrayRef, iConfigIndex ); if ( cfSearchNode != nil ) { if ( CFGetTypeID( cfSearchNode ) == CFStringGetTypeID() ) { //assume that the extracted strings will be significantly less than 1024 characters tmpBuff = new char[1024]; ::memset(tmpBuff,0,1024); if (CFStringGetCString(cfSearchNode, tmpBuff, cfBuffSize, kCFStringEncodingUTF8)) { outSearchNode = new char[1+strlen(tmpBuff)]; ::strcpy(outSearchNode, tmpBuff); pSearchNode = MakeListData(outSearchNode); delete(outSearchNode); if (pSearchNodeList == nil) { pSearchNodeList = pSearchNode; pTailSearchNode = pSearchNodeList; } else { while(pTailSearchNode->fNext != nil) { pTailSearchNode = pTailSearchNode->fNext; } pTailSearchNode->fNext = pSearchNode; } pSearchNode = nil; } delete( tmpBuff ); } } } // loop over search nodes //CFRelease( cfArrayRef ); // no since pointer only from Get } // if (cfArrayRef != nil) ie. an array of search nodes exists } // try catch( sInt32 err ) { siResult = err; } return( siResult ); } // ConfigList // -------------------------------------------------------------------------------- // * GetVersion // -------------------------------------------------------------------------------- char *CConfigs::GetVersion ( CFDictionaryRef configDict ) { char *outVersion = nil; CFStringRef cfStringRef = nil; char *tmpBuff = nil; CFIndex cfBuffSize = 1024; if ( CFDictionaryContainsKey( configDict, fXMLSearchPathVersionKeyString ) ) { cfStringRef = (CFStringRef)CFDictionaryGetValue( configDict, fXMLSearchPathVersionKeyString ); if ( cfStringRef != nil ) { if ( CFGetTypeID( cfStringRef ) == CFStringGetTypeID() ) { //assume that the extracted strings will be significantly less than 1024 characters tmpBuff = new char[1024]; ::memset(tmpBuff,0,1024); if (CFStringGetCString(cfStringRef, tmpBuff, cfBuffSize, kCFStringEncodingUTF8 )) { outVersion = new char[1+strlen(tmpBuff)]; ::strcpy(outVersion, tmpBuff); } delete( tmpBuff ); } } } // return if nil or not return( outVersion ); } // GetVersion // -------------------------------------------------------------------------------- // * GetSearchPolicy // -------------------------------------------------------------------------------- uInt32 CConfigs:: GetSearchPolicy ( CFDictionaryRef configDict ) { uInt32 searchPolicy = kNetInfoSearchPolicy; // default CFNumberRef cfNumber = 0; unsigned char cfNumBool = false; if ( CFDictionaryContainsKey( configDict, fXMLSearchPolicyKeyString ) ) { cfNumber = (CFNumberRef)CFDictionaryGetValue( configDict, fXMLSearchPolicyKeyString ); if ( cfNumber != nil ) { cfNumBool = CFNumberGetValue(cfNumber, kCFNumberIntType, &searchPolicy); //CFRelease(cfNumber); // no since pointer only from Get } } return( searchPolicy ); } // GetSearchPolicy // -------------------------------------------------------------------------------- // * GetListArray // -------------------------------------------------------------------------------- CFArrayRef CConfigs:: GetListArray ( CFDictionaryRef configDict ) { CFArrayRef cfArrayRef = nil; if ( CFDictionaryContainsKey( configDict, fXMLSearchPathArrayKeyString ) ) { cfArrayRef = (CFArrayRef)CFDictionaryGetValue( configDict, fXMLSearchPathArrayKeyString ); } // return if nil or not return( cfArrayRef ); } // GetListArray // -------------------------------------------------------------------------------- // * GetDHCPLDAPDictionary // -------------------------------------------------------------------------------- CFDictionaryRef CConfigs::GetDHCPLDAPDictionary ( ) { CFDictionaryRef cfDict = 0; if (fConfigDict) { if ( CFDictionaryContainsKey( fConfigDict, fXMLSearchDHCPLDAPString ) ) { cfDict = (CFDictionaryRef)CFDictionaryGetValue( fConfigDict, fXMLSearchDHCPLDAPString ); } } return( cfDict ); } // GetDHCPLDAPDictionary // -------------------------------------------------------------------------------- // * IsDHCPLDAPEnabled // checks if we should use DHCP LDAP nodes for the current location // -------------------------------------------------------------------------------- bool CConfigs::IsDHCPLDAPEnabled ( ) { bool dhcpLDAPEnabled = true; CFDictionaryRef cfDict = 0; CFBooleanRef cfBool = 0; SCDynamicStoreRef sysConfigRef = 0; CFStringRef currentLocation = 0; if (fConfigDict) { sysConfigRef = SCDynamicStoreCreate(NULL,CFSTR("DirectoryService Search Node"),NULL,NULL); if (sysConfigRef != 0) { currentLocation = SCDynamicStoreCopyLocation(sysConfigRef); if (currentLocation != 0) { if ( CFDictionaryContainsKey( fConfigDict, fXMLSearchDHCPLDAPString ) ) { cfDict = (CFDictionaryRef)CFDictionaryGetValue( fConfigDict, fXMLSearchDHCPLDAPString ); if ( cfDict != 0 && CFGetTypeID(cfDict) == CFDictionaryGetTypeID() ) { cfBool = (CFBooleanRef)CFDictionaryGetValue( cfDict, currentLocation ); if ( cfBool != 0 && CFGetTypeID(cfBool) == CFBooleanGetTypeID() ) { dhcpLDAPEnabled = CFBooleanGetValue(cfBool); } } } CFRelease(currentLocation); } CFRelease(sysConfigRef); } } return( dhcpLDAPEnabled ); } // IsDHCPLDAPEnabled // -------------------------------------------------------------------------------- // * SetDHCPLDAPDictionary // -------------------------------------------------------------------------------- void CConfigs::SetDHCPLDAPDictionary ( CFDictionaryRef dhcpLDAPdict ) { if (fConfigDict) { CFDictionarySetValue(fConfigDict, fXMLSearchDHCPLDAPString, dhcpLDAPdict); } } // SetDHCPLDAPDictionary // -------------------------------------------------------------------------------- // * SetSearchPolicy // -------------------------------------------------------------------------------- sInt32 CConfigs:: SetSearchPolicy ( uInt32 inSearchPolicy ) { CFNumberRef cfNumber = 0; sInt32 siResult = eDSNoErr; fSearchPolicy = inSearchPolicy; if (fConfigDict) { cfNumber = CFNumberCreate(NULL,kCFNumberIntType,&inSearchPolicy); if ( CFDictionaryContainsKey( fConfigDict, fXMLSearchPolicyKeyString ) ) { CFDictionaryReplaceValue(fConfigDict, fXMLSearchPolicyKeyString, cfNumber); } else { CFDictionarySetValue(fConfigDict, fXMLSearchPolicyKeyString, cfNumber); } if (cfNumber != 0) { CFRelease(cfNumber); cfNumber = 0; } } //KW need to error check this somehow return( siResult ); } // SetSearchPolicy // -------------------------------------------------------------------------------- // * SetListArray // -------------------------------------------------------------------------------- sInt32 CConfigs:: SetListArray ( CFMutableArrayRef inCSPArray ) { sInt32 siResult = eDSNoErr; if (fConfigDict) { if ( CFDictionaryContainsKey( fConfigDict, fXMLSearchPathArrayKeyString ) ) { CFDictionaryReplaceValue(fConfigDict, fXMLSearchPathArrayKeyString, (const void *) inCSPArray); } else { CFDictionarySetValue(fConfigDict, fXMLSearchPathArrayKeyString, (const void *) inCSPArray); } } //KW need to error check this somehow return( siResult ); } // SetListArray // --------------------------------------------------------------------------- // * MakeListData // --------------------------------------------------------------------------- sSearchList *CConfigs::MakeListData ( char *inNodeName ) { sInt32 siResult = eDSNoErr; sSearchList *listOut = nil; try { listOut = (sSearchList *) ::calloc( 1, sizeof(sSearchList)); if ( listOut != nil ) { //do nothing with return here since we know this is new //and we did a memset above siResult = CleanListData(listOut); listOut->fNodeName = new char[1+::strlen(inNodeName)]; ::strcpy(listOut->fNodeName,inNodeName); listOut->fDataList = ::dsBuildFromPathPriv( listOut->fNodeName, "/" ); //open the nodes lazily when they are actually needed /* if (fDirRef == 0) { siResult = ::dsOpenDirService( &fDirRef ); if ( siResult != eDSNoErr ) throw( (sInt32)eDSOpenFailed ); } siResult = ::dsOpenDirNode( fDirRef, listOut->fDataList, &listOut->fNodeRef ); if ( siResult != eDSNoErr ) { DBGLOG2( kLogPlugin, "Failed to open node: %s with error: %l", listOut->fNodeName, siResult ); DBGLOG( kLogPlugin, "Will attempt to open again later?" ); siResult = eDSNoErr; } else { DBGLOG1( kLogPlugin, " Node Reference = %l", listOut->fNodeRef ); listOut->fOpened = true; } */ } } catch( sInt32 err ) { siResult = err; } return( listOut ); } // MakeListData // --------------------------------------------------------------------------- // * CleanListData // --------------------------------------------------------------------------- sInt32 CConfigs::CleanListData ( sSearchList *inList ) { sInt32 siResult = eDSNoErr; if ( inList != nil ) { if (inList->fNodeName != nil) { delete ( inList->fNodeName ); } inList->fOpened = false; inList->fPreviousOpenFailed = false; if (inList->fNodeRef != 0) { ::dsCloseDirNode(inList->fNodeRef); // don't check error code inList->fNodeRef = 0; } inList->fNext = nil; if (inList->fDataList != nil) { dsDataListDeallocatePriv ( inList->fDataList ); //need to free the header as well free( inList->fDataList ); inList->fDataList = nil; } } return( siResult ); } // CleanListData