#include <stdio.h> #include <unistd.h> #include <CoreFoundation/CFString.h> #include <SystemConfiguration/SystemConfiguration.h> #include <sys/wait.h> #include <stdlib.h> #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> #include <dns.h> #include <dns_util.h> #include <sysexits.h> #include <DirectoryService/DirServices.h> #include <DirectoryService/DirServicesConst.h> #include <DirectoryService/DirServicesTypes.h> #include <DirectoryService/DirServicesUtils.h> #include "Common.h" #include <PasswordServer/ReplicaFile.h> #define kPWConfigDefaultRecordName "passwordserver" #define kPWConfigRecordPrefix "passwordserver_" extern "C" { char* ReplaceKerberosAddrs( const char *inValue, const char *inOldIP, const char *inNewIP, const char *inOldHostName, const char *inNewHostName ); int UpdateKerberosPrincipals(const char* node, const char *inNewHostName); FILE *gLogFileDesc = NULL; }; tDirStatus DoNodeAuth( const tDirReference inDirRef, const tDirNodeReference inDirNodeRef, const char* inUserName, const char* inPass ) { tDirStatus dirStatus = eDSNoErr; tDataBufferPtr authRequestBuffer = NULL; tDataBufferPtr authResponseBuffer = NULL; tContextData continueData = NULL; tDataNodePtr authType = NULL; long authRequestBufferSize = 0; long curOffset = 0; long userNameLength = 0; long passwordLength = 0; authType = dsDataNodeAllocateString( inDirRef, kDSStdAuthNodeNativeClearTextOK ); if( authType == NULL ) return eMemoryAllocError; userNameLength = strlen( inUserName ); passwordLength = strlen( inPass ); authResponseBuffer = dsDataBufferAllocate( inDirRef, 512 ); // Enough for the response. if( authResponseBuffer == NULL ) { dsDataNodeDeAllocate( inDirRef, authType ); return eMemoryAllocError; } //how big should the request buffer be? authRequestBufferSize += sizeof( userNameLength ) + userNameLength; authRequestBufferSize += sizeof( passwordLength ) + passwordLength; //allocate the request buffer authRequestBuffer = dsDataBufferAllocate( inDirRef, authRequestBufferSize ); if( authRequestBuffer == NULL ) { dsDataBufferDeAllocate( inDirRef, authResponseBuffer ); dsDataNodeDeAllocate( inDirRef, authType ); return eMemoryAllocError; } //populate the request buffer //user name first memcpy( &(authRequestBuffer->fBufferData[curOffset]), &userNameLength, sizeof( userNameLength ) ); curOffset += sizeof( userNameLength ); memcpy( &(authRequestBuffer->fBufferData[curOffset]), inUserName, userNameLength ); curOffset += userNameLength; //now the password memcpy( &(authRequestBuffer->fBufferData[curOffset]), &passwordLength, sizeof( passwordLength ) ); curOffset += sizeof( passwordLength ); memcpy( &(authRequestBuffer->fBufferData[curOffset]), inPass, passwordLength ); curOffset += passwordLength; authRequestBuffer->fBufferLength = curOffset; dirStatus = dsDoDirNodeAuth( inDirNodeRef, authType, FALSE, authRequestBuffer, authResponseBuffer, &continueData ); dsDataBufferDeAllocate( inDirRef, authRequestBuffer ); dsDataBufferDeAllocate( inDirRef, authResponseBuffer ); dsDataNodeDeAllocate( inDirRef, authType ); return dirStatus; } tDirStatus OpenRecordFromEntry( const tDirReference inDirRef, const tDirNodeReference inDirNodeRef, tRecordEntry* recEntry, tRecordReference* outRecordRef ) { tDirStatus dirStatus = eDSNoErr; char* recNameStr = NULL; char* recTypeStr = NULL; tDataNodePtr recName = NULL; tDataNodePtr recType = NULL; dirStatus = dsGetRecordNameFromEntry( recEntry, &recNameStr ); if (dirStatus == eDSNoErr) dirStatus = dsGetRecordTypeFromEntry( recEntry, &recTypeStr ); if (dirStatus == eDSNoErr) recName = dsDataNodeAllocateString( inDirRef, recNameStr ); if ( recName != NULL ) { recType = dsDataNodeAllocateString( inDirRef, recTypeStr ); if ( recType != NULL ) { dirStatus = dsOpenRecord( inDirNodeRef, recType, recName, outRecordRef ); dsDataNodeDeAllocate( inDirRef, recType ); } dsDataNodeDeAllocate( inDirRef, recName ); } //printf("Opening record %s returned %d\n", recNameStr, dirStatus); if (recNameStr != NULL) free(recNameStr); if (recTypeStr != NULL) free(recTypeStr); return dirStatus; } bool IsPartOfIP(char c) { return (isdigit(c) || (c == '.')); } bool IsPartOfHostName(char c) { return (isdigit(c) || isalpha(c) || (c == '-')); } char* ReplaceAddrs( const char *inValue, const char *inOldIP, const char *inNewIP, const char *inOldHostName, const char *inNewHostName ) { char *inValueCopy = NULL; char* returnValue = NULL; char* ipStr = NULL; char* hostStr = NULL; const char* tptr = NULL; int newHostLen = 0; int newFileLen = 0; int index = 0; int ipCount = 0; int hostCount = 0; // get count of inOldIP for (tptr = inValue; tptr != NULL;) { tptr = strstr(tptr, inOldIP); if (tptr != NULL) { tptr++; ipCount++; } } // get count of inOldHostName if (inOldHostName != NULL) { for (tptr = inValue; tptr != NULL;) { tptr = strstr(tptr, inOldHostName); if (tptr != NULL) { tptr++; hostCount++; } } } if (ipCount > 0 || hostCount > 0) { // calculate new size if (inNewHostName != NULL) newHostLen = strlen(inNewHostName); newFileLen = strlen(inValue) + strlen(inNewIP) * ipCount + newHostLen * hostCount; inValueCopy = (char *) malloc(newFileLen); if (inValueCopy == NULL) return NULL; returnValue = (char *) malloc(newFileLen); if (returnValue == NULL) return NULL; strcpy(inValueCopy, inValue); // replace instances of the IP address for (index = 0; index < ipCount; index++) { ipStr = strstr(inValueCopy, inOldIP); // check that found strings are not substrings if (ipStr != NULL) { if ((ipStr != inValueCopy) && IsPartOfIP(*(ipStr - 1))) ipStr = NULL; else if (IsPartOfIP(*(ipStr + strlen(inOldIP)))) ipStr = NULL; } if (ipStr != NULL) { strcpy(returnValue, inValueCopy); ipStr = strstr(returnValue, inOldIP); if (ipStr != NULL) { char* ipEnd = ipStr + strlen(inOldIP); memmove(ipEnd + strlen(inNewIP) - strlen(inOldIP), ipEnd, strlen(ipEnd) + 1); memcpy(ipStr, inNewIP, strlen(inNewIP)); } } strcpy(inValueCopy, returnValue); } // replace instances of the host name for (index = 0; index < hostCount; index++) { hostStr = strstr(inValueCopy, inOldHostName); // check that found strings are not substrings if (hostStr != NULL) { if ((hostStr != inValueCopy) && IsPartOfHostName(*(hostStr - 1))) hostStr = NULL; else if (IsPartOfHostName(*(hostStr + strlen(inOldHostName)))) hostStr = NULL; } if (hostStr != NULL) { strcpy(returnValue, inValueCopy); hostStr = strstr(returnValue, inOldHostName); if (hostStr != NULL) { char* hostEnd = hostStr + strlen(inOldHostName); memmove(hostEnd + strlen(inNewHostName) - strlen(inOldHostName), hostEnd, strlen(hostEnd) + 1); memcpy(hostStr, inNewHostName, strlen(inNewHostName)); } } strcpy(inValueCopy, returnValue); } } if (inValueCopy != NULL) free(inValueCopy); //if (returnValue != NULL) // printf("Swtiched %s to %s\n", inValue, returnValue); return returnValue; } void ConvertRecordAttributes( const tDirReference inDirRef, tDirNodeReference inDirNodeRef, const char *inOldIP, const char *inNewIP, const char *inOldHostName, const char *inNewHostName, char* inRecordType, char* in1stAttributeName, ...) { tDataBuffer *tDataBuff = NULL; long status = eDSNoErr; tContextData context = nil; tDataList recordTypeList; tDataList recordNameList; tDataList attributeList; unsigned long j = 0; unsigned long k = 0; unsigned long recIndex = 0; unsigned long recCount = 0; tRecordEntry *recEntry = nil; tAttributeListRef attrListRef = 0; tAttributeValueListRef valueRef = 0; tAttributeEntry *pAttrEntry = nil; tAttributeValueEntry *pValueEntry = nil; tAttributeValueEntry *pNewPWAttrValue = nil; tRecordReference recRef = 0; unsigned long buffSize = 4096; va_list args; va_start( args, in1stAttributeName ); memset(&attributeList, 0, sizeof(attributeList)); memset(&recordTypeList, 0, sizeof(recordTypeList)); memset(&recordNameList, 0, sizeof(recordNameList)); do { tDataBuff = dsDataBufferAllocate( inDirRef, buffSize ); if ( tDataBuff == NULL ) break; status = dsBuildListFromStringsAllocV( inDirRef, &attributeList, in1stAttributeName, args ); if( status != eDSNoErr ) break; status = dsBuildListFromStringsAlloc ( inDirRef, &recordTypeList, inRecordType, NULL ); if( status != eDSNoErr ) break; status = dsBuildListFromStringsAlloc ( inDirRef, &recordNameList, kDSRecordsAll, NULL ); if( status != eDSNoErr ) break; do { do { status = dsGetRecordList( inDirNodeRef, tDataBuff, &recordNameList, eDSExact, &recordTypeList, &attributeList, false, &recCount, &context ); if ( status == eDSBufferTooSmall ) { buffSize *= 2; // a safety for a runaway condition if ( buffSize > 1024 * 1024 ) break; dsDataBufferDeAllocate( inDirRef, tDataBuff ); tDataBuff = dsDataBufferAllocate( inDirRef, buffSize ); if ( tDataBuff == NULL ) { status = eMemoryError; break; } } } while ( status == eDSBufferTooSmall ); if (status != eDSNoErr) break; for ( recIndex = 1; recIndex <= recCount; recIndex++ ) { status = dsGetRecordEntry( inDirNodeRef, tDataBuff, recIndex, &attrListRef, &recEntry ); if ( status != eDSNoErr && recEntry == NULL ) continue; for ( j = 1; (j <= recEntry->fRecordAttributeCount) && (status == eDSNoErr); j++ ) { status = dsGetAttributeEntry( inDirNodeRef, tDataBuff, attrListRef, j, &valueRef, &pAttrEntry ); if ( status == eDSNoErr && pAttrEntry != NULL ) { for ( k = 1; (k <= pAttrEntry->fAttributeValueCount) && (status == eDSNoErr); k++ ) { status = dsGetAttributeValue( inDirNodeRef, tDataBuff, k, valueRef, &pValueEntry ); if ( status == eDSNoErr && pValueEntry != NULL ) { char* valueStr = (char*)(pValueEntry->fAttributeValueData.fBufferData); char* newValue; if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDS1AttrXMLPlist ) == 0 ) newValue = ReplaceKerberosAddrs(valueStr, inOldIP, inNewIP, inOldHostName, inNewHostName); else if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrAuthenticationAuthority ) == 0 ) newValue = ReplaceAddrs(valueStr, inOldIP, inNewIP, nil, nil); // don't convert hostnames, only IP addresses else newValue = ReplaceAddrs(valueStr, inOldIP, inNewIP, inOldHostName, inNewHostName); if (newValue != NULL) { OpenRecordFromEntry(inDirRef, inDirNodeRef, recEntry, &recRef); if (recRef != 0) pNewPWAttrValue = dsAllocAttributeValueEntry(inDirRef, pValueEntry->fAttributeValueID, newValue, strlen(newValue)); if ( pNewPWAttrValue != nil ) { status = dsSetAttributeValue( recRef, &pAttrEntry->fAttributeSignature, pNewPWAttrValue ); //printf("dsSetAttributeValue returned %ld\n", status); dsDeallocAttributeValueEntry( inDirRef, pNewPWAttrValue ); pNewPWAttrValue = nil; } free(newValue); } dsDeallocAttributeValueEntry( inDirRef, pValueEntry ); } } dsDeallocAttributeEntry( inDirRef, pAttrEntry ); dsCloseAttributeValueList(valueRef); } } dsDeallocRecordEntry( inDirRef, recEntry ); dsCloseAttributeList(attrListRef); } } while ( status == eDSNoErr && context != NULL ); } while(false); dsDataListDeallocate( inDirRef, &attributeList ); dsDataListDeallocate( inDirRef, &recordTypeList ); dsDataListDeallocate( inDirRef, &recordNameList ); if (tDataBuff != nil) dsDataBufferDeAllocate(inDirRef, tDataBuff); } void UpdatePSReplicas(const char *inOldIP, const char* inNewIP) { CFMutableDictionaryRef replicaDict = NULL; ReplicaFile *replicaFile = [ReplicaFile new]; char myAddresses[256] = {0}; CFStringRef replicaNameString = NULL; char newIP[256]; strlcpy(newIP,inNewIP, sizeof(newIP)); replicaNameString = [replicaFile getNameFromIPAddress:inOldIP]; replicaDict = [replicaFile getReplicaByName:replicaNameString]; GetPWServerAddresses( myAddresses ); if ( strstr( myAddresses, inOldIP ) != NULL ) SetPWServerAddress( NULL, NULL, newIP, false, NULL, NULL ); if ( replicaDict != NULL ) { [replicaFile addIPAddress:inNewIP orReplaceIP:inOldIP inReplica:replicaDict]; [replicaFile saveXMLData]; CFRelease( replicaDict ); } UpdateReplicaList( inOldIP, inNewIP ); } #define SLAPPATH "/usr/sbin/slapconfig" void CallSlapConfig( const char *inOldIP, const char *inNewIP, const char *inOldHostName, const char *inNewHostName ) { pid_t pid; int status; struct stat sb; const char* argv[7]; status = stat( SLAPPATH, &sb ); if ( status != 0 ) return; argv[0] = "slapconfig"; argv[1] = "-changeip"; argv[2] = inOldIP; argv[3] = inNewIP; argv[4] = inOldHostName; argv[5] = inNewHostName; argv[6] = nil; pid = fork(); if (pid == -1) return; /* Handle the child */ if (pid == 0) { int result = -1; result = execv(SLAPPATH, (char* const*)argv); if (result == -1) { _exit(1); } /* This should never be reached */ _exit(1); } waitpid(pid, &status, 0); return; } void ConvertRecords( const char *inDirPath, const char *inOldIP, const char *inNewIP, const char *inOldHostName, const char *inNewHostName ) { tDirReference dsRef = 0; tDirNodeReference nodeRef = 0; long status = eDSNoErr; tDataList *nodeName = nil; bool isLocalNode = false; bool isLDAPINode = false; isLocalNode = (strncmp(inDirPath, "/Local", sizeof("/Local") - 1) == 0); isLDAPINode = (strstr(inDirPath, "ldapi") != NULL); status = dsOpenDirService( &dsRef ); if ( status != eDSNoErr ) { fprintf( stderr, "ERROR: could not open Directory Services (error = %ld)\n", status ); exit( EX_UNAVAILABLE ); } if ( isLDAPINode ) inDirPath = "/LDAPv3/ldapi://%2Fvar%2Frun%2Fldapi"; nodeName = dsBuildFromPath( dsRef, inDirPath, "/" ); status = dsOpenDirNode( dsRef, nodeName, &nodeRef ); dsDataListDeallocate( dsRef, nodeName ); if ( status != eDSNoErr ) { fprintf(stderr, "Error %ld opening node %s\n", status, inDirPath); exit( EX_UNAVAILABLE ); } // authenticate if needed if ( !isLocalNode && !isLDAPINode ) { int tries = 0; do { char userName[256]; char* password; printf("Enter admin name for node %s: ", inDirPath); fgets(userName, 255, stdin); if (strlen(userName) > 0 && userName[strlen(userName)-1] == '\n') userName[strlen(userName)-1] = '\0'; password = getpass("Password:"); status = DoNodeAuth(dsRef, nodeRef, userName, password); if (status != eDSNoErr) { fprintf(stderr, "Error %ld authenticating to node %s\n", status, inDirPath); if (++tries == 3) { fprintf(stderr, "Too many tries, exiting\n"); exit(1); } } } while (status != eDSNoErr); } // First do User Records ConvertRecordAttributes(dsRef, nodeRef, inOldIP, inNewIP, inOldHostName, inNewHostName, kDSStdRecordTypeUsers, kDSNAttrAuthenticationAuthority, kDS1AttrNFSHomeDirectory, kDSNAttrHomeDirectory, kDSNAttrRecordName, nil); // Then machine records if (!isLocalNode) ConvertRecordAttributes(dsRef, nodeRef, inOldIP, inNewIP, inOldHostName, inNewHostName, kDSStdRecordTypeMachines, kDSNAttrIPAddress, kDSNAttrRecordName, kDSNAttrDNSName, nil); else ConvertRecordAttributes(dsRef, nodeRef, inOldIP, inNewIP, inOldHostName, inNewHostName, kDSStdRecordTypeMachines, kDSNAttrIPAddress, kDSNAttrRecordName, kDSNAttrDNSName, kDSNativeAttrTypePrefix "serves", nil); // need serves attribute too for hostname changes // Then computer records ConvertRecordAttributes(dsRef, nodeRef, inOldIP, inNewIP, inOldHostName, inNewHostName, kDSStdRecordTypeComputers, kDSNAttrAuthenticationAuthority,kDSNAttrIPAddress, kDSNAttrRecordName, nil); // Then mount records ConvertRecordAttributes(dsRef, nodeRef, inOldIP, inNewIP, inOldHostName, inNewHostName, kDSStdRecordTypeMounts, kDSNAttrVFSOpts, kDSNAttrRecordName, nil); // Then config records ConvertRecordAttributes(dsRef, nodeRef, inOldIP, inNewIP, inOldHostName, inNewHostName, kDSStdRecordTypeConfig, kDSNAttrLDAPReadReplicas, kDSNAttrLDAPWriteReplicas, kDS1AttrPasswordServerLocation, kDS1AttrPasswordServerList, kDS1AttrXMLPlist, kDSNAttrRecordName, nil); // update master property in top level if (isLocalNode) { tRecordReference recRef = 0; tDataNodePtr recName = dsDataNodeAllocateString( dsRef, "/" ); if ( recName != NULL ) { tDataNodePtr recType = dsDataNodeAllocateString( dsRef, kDSNativeRecordTypePrefix "/" ); if ( recType != NULL ) { status = dsOpenRecord( nodeRef, recType, recName, &recRef ); dsDataNodeDeAllocate( dsRef, recType ); } dsDataNodeDeAllocate( dsRef, recName ); } if (status == eDSNoErr) { tAttributeValueEntryPtr masterAttr = nil; tAttributeValueEntryPtr newValue = nil; char* newValueStr = nil; tDataNodePtr attrType = dsDataNodeAllocateString(dsRef, kDSNativeAttrTypePrefix "master"); status = dsGetRecordAttributeValueByIndex(recRef,attrType,1,&masterAttr); if (status == eDSNoErr) { if ((strncmp(masterAttr->fAttributeValueData.fBufferData,inOldIP,strlen(inOldIP)) == 0) && (masterAttr->fAttributeValueData.fBufferData[strlen(inOldIP)] == '/')) { // found a matching IP newValueStr = (char*)calloc(strlen(masterAttr->fAttributeValueData.fBufferData)+strlen(inNewIP)+1,1); strcpy(newValueStr,inNewIP); strcat(newValueStr,masterAttr->fAttributeValueData.fBufferData + strlen(inOldIP)); newValue = dsAllocAttributeValueEntry(dsRef,masterAttr->fAttributeValueID, newValueStr,strlen(newValueStr)); status = dsSetAttributeValue(recRef,attrType,newValue); } else if (inOldHostName != nil && (strncmp(masterAttr->fAttributeValueData.fBufferData,inOldHostName,strlen(inOldHostName)) == 0) && (masterAttr->fAttributeValueData.fBufferData[strlen(inOldHostName)] == '/')) { // found a matching hostname newValueStr = (char*)calloc(strlen(masterAttr->fAttributeValueData.fBufferData)+strlen(inNewHostName)+1,1); strcpy(newValueStr,inNewHostName); strcat(newValueStr,masterAttr->fAttributeValueData.fBufferData + strlen(inOldHostName)); newValue = dsAllocAttributeValueEntry(dsRef,masterAttr->fAttributeValueID, newValueStr,strlen(newValueStr)); status = dsSetAttributeValue(recRef,attrType,newValue); } } } } dsCloseDirNode(nodeRef); } void UpdateIPAddrAndHostNameInFile( const char* filePath, const char *inOldIP, const char *inNewIP, const char *inOldHostName, const char *inNewHostName) { char* hostConfigBuffer; char* newValue; int fd; struct stat sb; int result; result = stat(filePath, &sb); if (result != 0) return; hostConfigBuffer = (char*)malloc(sb.st_size + 1); fd = open(filePath, O_RDWR, 0); if (fd == -1) return; result = read(fd, hostConfigBuffer, sb.st_size); hostConfigBuffer[result] = 0; newValue = ReplaceAddrs(hostConfigBuffer, inOldIP, inNewIP, inOldHostName, inNewHostName); if (newValue != NULL) { lseek(fd, 0, SEEK_SET); ftruncate(fd, 0); result = write(fd, newValue, strlen(newValue)); free(newValue); } free(hostConfigBuffer); close(fd); } void UpdateHostConfig(const char *inOldIP, const char *inNewIP, const char *inOldHostName, const char *inNewHostName) { UpdateIPAddrAndHostNameInFile( "/etc/hostconfig", inOldIP, inNewIP, inOldHostName, inNewHostName ); } void UpdateSMBConf(const char *inOldIP, const char *inNewIP, const char *inOldHostName, const char *inNewHostName) { char oldHostName[MAXHOSTNAMELEN] = { 0, }; char newHostName[MAXHOSTNAMELEN] = { 0, }; // smb uses unqualified name, so let's unqualify the name just in case if( NULL != inOldHostName && NULL != inNewHostName ) { strcpy( oldHostName, inOldHostName ); strcpy( newHostName, inNewHostName ); char *pTemp = strchr( oldHostName, '.' ); if( NULL != pTemp ) *pTemp = '\0'; pTemp = strchr( newHostName, '.' ); if( NULL != pTemp ) *pTemp = '\0'; inOldHostName = oldHostName; inNewHostName = newHostName; } UpdateIPAddrAndHostNameInFile( "/etc/smb.conf", inOldIP, inNewIP, inOldHostName, inNewHostName ); } void Usage() { fprintf(stderr, "Usage: changeip_ds <dir node path> <oldIP> <newIP> [<oldHost> <newHost>]\n"); fprintf(stderr, "\teg: changeip_ds /LDAPv3/127.0.0.1 11.0.1.10 11.0.1.12 server10 server12\n\n"); fprintf(stderr, "Use - for node path to update the local node only, \n\teg. changeip_ds - 11.0.1.10 11.0.1.12\n"); } char *getReverseIPString( const char *inAddress ) { unsigned char addr[INET_ADDRSTRLEN] = { 0, }; Boolean bIPv4 = true; char *pReturnString = NULL; if( inet_net_pton(AF_INET, inAddress, &addr, INET_ADDRSTRLEN) <= 0 ) { bIPv4 = false; if( inet_net_pton(AF_INET6, inAddress, &addr, INET_ADDRSTRLEN) <= 0 ) { return nil; } } if( bIPv4 ) { pReturnString = (char *) calloc( 64, sizeof(char) ); snprintf( pReturnString, 32, "%u.%u.%u.%u.in-addr.arpa.", addr[3], addr[2], addr[1], addr[0] ); } else { int s = 0; char ptr_name[128]; int x = sizeof(ptr_name); int n; int i; /* * build IPv6 "nibble" PTR query name (RFC 1886, RFC 3152) * N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.ip6.arpa. */ for (i = sizeof(addr) - 1; i >= 0; i--) { n = snprintf( &ptr_name[s], x, "%x.%x.", ( addr[i] & 0xf), ((addr[i] >> 4) & 0xf)); if ((n == -1) || (n >= x)) { goto done; } s += n; x -= n; } n = snprintf(&ptr_name[s], x, "ip6.arpa."); if (n != -1 && n < x) { goto done; } pReturnString = strdup( ptr_name ); } done: return pReturnString; } char *_GetCStringFromCFString( CFStringRef cfString ) { char *pReturn = NULL; if( NULL != cfString ) { CFIndex iBufferSize = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfString), kCFStringEncodingUTF8) + 1; pReturn = (char *) malloc( iBufferSize ); if( CFStringGetCString( cfString, pReturn, iBufferSize, kCFStringEncodingUTF8 ) == 0 ) { free( pReturn ); pReturn = NULL; } } return pReturn; } char *lookupReverseInDNS( CFStringRef inAddress ) { char *pAddress = _GetCStringFromCFString( inAddress ); char *reversePTR = NULL; char *reverseName = NULL; reversePTR = getReverseIPString( pAddress ); free( pAddress ); pAddress = NULL; if( NULL != reversePTR ) { // let's try to lookup our own hostname via DNS dns_handle_t dns = dns_open( NULL ); if( NULL != dns ) { uint16_t type = 0; uint16_t classtype = 0; dns_reply_t *reply = NULL; dns_type_number( "PTR", &type ); dns_class_number( "IN", &classtype ); reply = dns_lookup( dns, reversePTR, classtype, type ); if( NULL != reply ) { if ( (reply->header != NULL) && (reply->header->ancount > 0) ) { if( reply->header->ancount == 1 ) { dns_domain_name_record_t *record = reply->answer[0]->data.PTR; if( NULL != record && NULL != record->name ) { if( strcmp(record->name, "localhost") != 0 ) { reverseName = strdup( record->name ); } } } } dns_free_reply( reply ); reply = NULL; } dns_free( dns ); dns = NULL; } free( reversePTR ); reversePTR = NULL; } return reverseName; } void checkHostName( void ) { SCDynamicStoreRef cfStore = NULL; CFStringRef cfKey = NULL; CFStringRef cfGlobalKey = NULL; CFDictionaryRef cfGlobalIPv4 = NULL; CFStringRef cfPrimaryService = NULL; CFDictionaryRef cfServiceIPv4 = NULL; CFArrayRef cfPrimaryAddressList = NULL; CFStringRef cfPrimaryAddress = NULL; // let's get the primary IP address according to SC cfStore = SCDynamicStoreCreate(NULL, CFSTR("changeip_ds"), NULL, NULL); if( NULL != cfStore ) { cfGlobalKey = SCDynamicStoreKeyCreateNetworkGlobalEntity( kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCEntNetIPv4 ); if( NULL != cfGlobalKey ) { cfGlobalIPv4 = (CFDictionaryRef) SCDynamicStoreCopyValue( cfStore, cfGlobalKey ); if( NULL != cfGlobalIPv4 ) { cfPrimaryService = (CFStringRef) CFDictionaryGetValue( cfGlobalIPv4, kSCDynamicStorePropNetPrimaryService ); if( NULL != cfPrimaryService ) { cfKey = SCDynamicStoreKeyCreateNetworkServiceEntity( kCFAllocatorDefault, kSCDynamicStoreDomainState, cfPrimaryService, kSCEntNetIPv4 ); if( NULL != cfKey ) { cfServiceIPv4 = (CFDictionaryRef) SCDynamicStoreCopyValue( cfStore, cfKey ); if( NULL != cfServiceIPv4 ) { cfPrimaryAddressList = (CFArrayRef) CFDictionaryGetValue( cfServiceIPv4, kSCPropNetIPv4Addresses ); if( NULL != cfPrimaryAddressList && CFArrayGetCount(cfPrimaryAddressList) != 0 ) { cfPrimaryAddress = (CFStringRef) CFArrayGetValueAtIndex( cfPrimaryAddressList, 0 ); if( NULL != cfPrimaryAddress ) { CFRetain( cfPrimaryAddress ); } } CFRelease( cfServiceIPv4 ); cfServiceIPv4 = NULL; } CFRelease( cfKey ); cfKey = NULL; } } CFRelease( cfGlobalIPv4 ); cfGlobalIPv4 = NULL; } CFRelease( cfGlobalKey ); cfGlobalKey = NULL; } } // only a need to continue if we have a valid IP address if (NULL != cfPrimaryAddress) { char *reverseName = lookupReverseInDNS( cfPrimaryAddress ); char *primaryAddress = _GetCStringFromCFString( cfPrimaryAddress ); char oldHostName[MAXHOSTNAMELEN] = { 0, }; (void) gethostname( oldHostName, MAXHOSTNAMELEN ); printf( "\n" ); printf( "Primary address = %s\n\n", primaryAddress ); printf( "Current HostName = %s\n", oldHostName ); if ( NULL != reverseName) { printf( "DNS HostName = %s\n", reverseName ); if( strcmp(reverseName, oldHostName) == 0 ) { printf( "\nThe names match. There is nothing to change.\n" ); } else { // test for /LDAPv3/127.0.0.1 node tDirReference dsRef = 0; tDirNodeReference nodeRef = 0; tDirStatus status = eDSNoErr; tDataList *nodeName = NULL; bool hasLocalLDAPNode = false; status = dsOpenDirService( &dsRef ); if ( status == eDSNoErr ) { nodeName = dsBuildListFromStrings( dsRef, "LDAPv3", "127.0.0.1", NULL ); if ( nodeName != NULL ) { status = dsOpenDirNode( dsRef, nodeName, &nodeRef ); if ( status == eDSNoErr ) { hasLocalLDAPNode = true; dsCloseDirNode( nodeRef ); } dsDataListDeallocate( dsRef, nodeName ); } dsCloseDirService( dsRef ); } printf( "\nTo fix the hostname please run /usr/sbin/changeip for your system with the\n" ); printf( "appropriate directory with the following values\n\n" ); printf( " /usr/sbin/changeip <node> %s %s %s %s\n\n", primaryAddress, primaryAddress, oldHostName, reverseName ); printf( "example:\n\n /usr/sbin/changeip %s %s %s %s %s\n\n", hasLocalLDAPNode ? "/LDAPv3/127.0.0.1" : "-", primaryAddress, primaryAddress, oldHostName, reverseName ); } } else { printf( "\nThe DNS hostname is not available, please repair DNS and re-run this tool.\n\n" ); } CFRelease( cfPrimaryAddress ); cfPrimaryAddress = NULL; } else { fprintf( stderr, "Unable to determine Primary IP address.\n\n" ); } } int main (int argc, const char * argv[]) { const char* oldHostName = nil; const char* newHostName = nil; if (getuid() != 0) { fprintf(stderr, "%s must be run as root\n", argv[0]); exit(1); } if (argc == 2 && strcasecmp(argv[1], "-checkhostname") == 0) { checkHostName(); exit(0); } // this is used by the changeIP script to preflight check the IP address name, not exposed // in the usage if (argc == 3 && strcasecmp(argv[1], "-nameforaddress") == 0) { CFStringRef cfAddress = CFStringCreateWithCString( kCFAllocatorDefault, argv[2], kCFStringEncodingUTF8 ); char *pName = lookupReverseInDNS( cfAddress ); if( NULL != pName ) { printf( "%s\n", pName ); free( pName ); pName = NULL; exit( 0 ); } exit( ENOENT ); } if (argc != 4 && argc != 6) { Usage(); exit(1); } if (argc == 6) { oldHostName = argv[4]; newHostName = argv[5]; } printf("Updating local node\n"); ConvertRecords("/Local/Default", argv[2], argv[3], oldHostName, newHostName); if (strcmp(argv[1], "-") != 0) { printf("Updating node %s\n", argv[1]); ConvertRecords(argv[1], argv[2], argv[3], oldHostName, newHostName); } printf("Updating Password Server config\n"); UpdatePSReplicas(argv[2], argv[3]); printf("Updating Open Directory config\n"); CallSlapConfig(argv[2], argv[3], oldHostName, newHostName); printf("Updating hostconfig file\n"); UpdateHostConfig(argv[2], argv[3], oldHostName, newHostName); printf("Updating smb.conf file\n"); UpdateSMBConf(argv[2], argv[3], oldHostName, newHostName); printf("Updating Kerberos Service Principals and keytabs\n"); UpdateKerberosPrincipals(argv[1], newHostName); printf("Finished updating Kerberos\n"); return 0; }