/* * Copyright (c) 2007 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ #include #include #include #include #include #include #include #include #include #include "KerberosServiceSetup.h" #include "FTPAccessFile.h" #import "PSUtilitiesDefs.h" #include #include #define kAFPConfigPath "/Library/Preferences/com.apple.AppleFileServer.plist" #define kAFPPrincipalKey "kerberosPrincipal" #define kAFPPidFilePath "/var/run/AppleFileServer.pid" #define kFTPConfigPath "/Library/FTPServer/Configuration/ftpaccess" #define kFTPPrincipalKey "ktb5_principal" #define kFTPPidFilePath "/var/run/" #define kMailConfigPath "/etc/MailServicesOther.plist" #define kSMTPConfigKey "postfix" #define kSMTPPrincipalKey "smtp_principal" #define kIMAPConfigKey "cyrus" #define kIMAPPrincipalKey "imap_principal" #define kPOPConfigKey "cyrus" #define kPOPPrincipalKey "pop_principal" #define kPcastConfigPath "/var/pcast/server/kerberos_principals.plist" #define kPcastPrincipalKey "PodcastProducerServicePrincipals" #define kSMBConfigTool "/usr/share/servermgrd/cgi-bin/servermgr_smb" #define kVPNConfigPath "/Library/Preferences/SystemConfiguration/com.apple.RemoteAccessServers.plist" #define kVPNPrincipalKey "KerberosServicePrincipalName" #define kVPNServerKey "Servers" #define kVPNServiceKey "com.apple.ppp.l2tp" #define kVPNPPTPServiceKey "com.apple.ppp.pptp" #define kVPNEAPKey "EAP" #define kXGridConfigPath "/etc/xgrid/controller/service-principal" #define kApacheConfigTool "/usr/sbin/apache-kerberos" static CFDictionaryRef CreateMyPropertyListFromFile( CFURLRef fileURL, Boolean isMutable); static CFMutableDictionaryRef CreateVPNDefaults(void); static CFErrorRef OpenXGridPrincipalFile(int openFlags, int *configFileRef); static CFMutableDictionaryRef CreateDictionaryFromFD(int inFd, Boolean inMakeMutable); static CFErrorRef MyCFErrorCreate(CFStringRef domain, CFIndex code, CFStringRef description); #pragma mark - #pragma mark File Services #pragma mark - CFErrorRef SetAFPPrincipal(CFStringRef inPrincipal) { CFErrorRef theError = NULL; CFMutableDictionaryRef theConfig = NULL; CFURLRef thePathURL = NULL; CFDataRef theData = NULL; CFStringRef logString = NULL; const void *keys[1]; const void *values[1]; CFIndex dataLength; int fd; pid_t serverPid = 0; size_t len; UInt8 theBuffer[16]; mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; // 644 -rw-r--r-- thePathURL = CFURLCreateFromFileSystemRepresentation(NULL, (UInt8 *)kAFPConfigPath, strlen(kAFPConfigPath), false); if ( thePathURL != NULL ) { // if the config file exists open it & parse it theConfig = (CFMutableDictionaryRef) CreateMyPropertyListFromFile(thePathURL, true); CFRelease( thePathURL ); thePathURL = NULL; } if (theConfig != NULL) { // and add the principal name or overwrite CFDictionarySetValue(theConfig, CFSTR(kAFPPrincipalKey), inPrincipal); } else { // else create minimal config dictionary keys[0] = CFSTR(kAFPPrincipalKey); values[0] = inPrincipal; theConfig = (CFMutableDictionaryRef)CFDictionaryCreate(NULL, keys, values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } theData = CFPropertyListCreateXMLData(NULL, theConfig); if (theData != NULL) { dataLength = CFDataGetLength(theData); // open - truncate if ((fd = open(kAFPConfigPath, O_RDWR | O_CREAT | O_TRUNC, mode)) == -1) { logString = CFStringCreateWithFormat(NULL, NULL, CFSTR("Error writing AFP config file at %s error = %d\n"), kAFPConfigPath, errno); theError = MyCFErrorCreate(kCFErrorDomainPOSIX, (CFIndex)errno, logString); if ( logString != NULL ) CFRelease( logString ); } else { write(fd, CFDataGetBytePtr(theData), dataLength); close(fd); } CFRelease(theData); } CFRelease(theConfig); // cause the afp server to reread its prefs: just need to HUP it. // get the pid of the afp server process if (theError == NULL) { bzero(theBuffer, sizeof(theBuffer)); fd = open(kAFPPidFilePath, O_RDONLY, 0); // open the file read only if (fd != -1) // open failed, file server is not running { // read the pid from the file len = read(fd, theBuffer, sizeof(theBuffer)); if (len != 0) serverPid = atoi((char *)theBuffer); close(fd); if (serverPid > 0) kill(serverPid,SIGHUP); } } return theError; } CFErrorRef SetFTPPrincipal(CFStringRef inPrincipal) { CFErrorRef theError = NULL; char buffer[1024]; if ( CFStringGetCString(inPrincipal, buffer, sizeof(buffer), kCFStringEncodingASCII) == false ) return MyCFErrorCreate(kCFErrorDomainPOSIX, (CFIndex)-2, NULL); try { FTPAccessFile *configFile = (FTPAccessFile *) new FTPAccessFile(); // set the principal name configFile->SetKerberosPrincipal(buffer); delete configFile; } catch(...) { theError = MyCFErrorCreate(kCFErrorDomainPOSIX, (CFIndex)-1, NULL); } // do not need to HUP the FTP server, every instance is a single connection return theError; } /* SetNFSPrincipal() */ CFErrorRef SetNFSPrincipal(CFStringRef inPrincipal) { return NULL; } /* from bug 3575788 to enable the active directory domaim member configuration role send the following xml command to /usr/share/servermgrd/cgi-bin/servermgr_smb command writeSettings configuration adminCommands serverRole domainmember changeRole 1 domain master local master realm MY.KERBEROS.REALM this will kerberize the smb service and should only be called for MS Kerberos realms. Please note the 'netbios name' and 'workgroup' are required and must be retrieved from the AD Plugin. (not currently available or needed, there were changes in the other tool) */ CFErrorRef SetSMBPrincipal(CFStringRef inPrincipal, CFStringRef inAdminName, const char *inPassword) { CFErrorRef theError = NULL; CFArrayRef tmpArray = NULL; CFIndex tmpInt; SCPreferencesRef prefs = NULL; prefs = SCPreferencesCreate(NULL, CFSTR("Password Server Plugin"), CFSTR(kSMBPreferencesAppID)); if (NULL == prefs) { theError = MyCFErrorCreate(kCFErrorDomainPOSIX, (CFIndex)-1, CFSTR("SetSMBPrincipal: Cannot create SMB preferences\n")); } else { // get the realm tmpArray = CFStringCreateArrayBySeparatingStrings(NULL, inPrincipal, CFSTR("@")); tmpInt = CFArrayGetCount(tmpArray); if (tmpInt != 2) { CFRelease(tmpArray); tmpArray = NULL; theError = MyCFErrorCreate(kCFErrorDomainPOSIX, (CFIndex)-1, CFSTR("SetSMBPrincipal: Cannot find the realm name\n")); } else { CFStringRef newValueStrRef = (CFStringRef)CFArrayGetValueAtIndex(tmpArray, tmpInt-1); CFPropertyListRef cfpRealmRef = NULL; cfpRealmRef = newValueStrRef; if (SCPreferencesSetValue(prefs, CFSTR(kSMBPrefKerberosRealm), cfpRealmRef)) { if (!SCPreferencesCommitChanges(prefs)) { syslog(LOG_ERR,"Error in adding the SMB principal"); theError = MyCFErrorCreate(kCFErrorDomainPOSIX, (CFIndex)-1, CFSTR("SetSMBPrincipal: Cannot set the SMB Principal name\n")); } else SCPreferencesApplyChanges(prefs); } } CFRelease(prefs); CFRelease(tmpArray); } return theError; } #pragma mark - #pragma mark Mail Services #pragma mark - /* We don't neeed to HUP the IMAP service */ CFErrorRef SetIMAPPrincipal(CFStringRef inPrincipal) { CFErrorRef theError = NULL; CFMutableDictionaryRef theConfig = NULL; CFMutableDictionaryRef theService = NULL; CFURLRef thePathURL = NULL; CFDataRef theData = NULL; CFStringRef logString = NULL; const void *keys[1]; const void *values[1]; CFIndex dataLength; int fd; mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; // 644 -rw-r--r-- thePathURL = CFURLCreateFromFileSystemRepresentation(NULL, (UInt8 *)kMailConfigPath, strlen(kMailConfigPath), false); // if the config file exists open it & parse it theConfig = (CFMutableDictionaryRef)CreateMyPropertyListFromFile(thePathURL, true); CFRelease( thePathURL ); thePathURL = NULL; if (theConfig != NULL) { theService = (CFMutableDictionaryRef)CFDictionaryGetValue(theConfig, CFSTR(kIMAPConfigKey)); // look for the imap config if (theService == NULL) { keys[0] = CFSTR(kIMAPPrincipalKey); values[0] = inPrincipal; theService = (CFMutableDictionaryRef)CFDictionaryCreate(NULL, keys, values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(theConfig, CFSTR(kIMAPConfigKey), theService); } else { // and add the principal name or overwrite CFDictionarySetValue(theService, CFSTR(kIMAPPrincipalKey), inPrincipal); } } else { // else create minimal config dictionary keys[0] = CFSTR(kIMAPPrincipalKey); values[0] = inPrincipal; theService = (CFMutableDictionaryRef)CFDictionaryCreate(NULL, keys, values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); keys[0] = CFSTR(kIMAPConfigKey); values[0] = theService; theConfig = (CFMutableDictionaryRef)CFDictionaryCreate(NULL, keys, values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } theData = CFPropertyListCreateXMLData(NULL, theConfig); if (theData != NULL) { dataLength = CFDataGetLength(theData); // open - truncate if ((fd = open(kMailConfigPath, O_RDWR | O_CREAT | O_TRUNC, mode)) == -1) { logString = CFStringCreateWithFormat(NULL, NULL, CFSTR("Error writing Mail config file at %s error = %d\n"), kMailConfigPath, errno); theError = MyCFErrorCreate(kCFErrorDomainPOSIX, (CFIndex)errno, logString); if ( logString != NULL ) CFRelease( logString ); } else { write(fd, CFDataGetBytePtr(theData), dataLength); close(fd); } CFRelease(theData); } CFRelease(theConfig); return theError; } /* We don't neeed to HUP the POP service */ CFErrorRef SetPOPPrincipal(CFStringRef inPrincipal) { CFErrorRef theError = NULL; CFMutableDictionaryRef theConfig = NULL; CFMutableDictionaryRef theService = NULL; CFURLRef thePathURL = NULL; CFDataRef theData = NULL; CFStringRef logString = NULL; const void *keys[1]; const void *values[1]; CFIndex dataLength; int fd; mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; // 644 -rw-r--r-- thePathURL = CFURLCreateFromFileSystemRepresentation(NULL, (UInt8 *)kMailConfigPath, strlen(kMailConfigPath), false); // if the config file exists open it & parse it theConfig = (CFMutableDictionaryRef)CreateMyPropertyListFromFile(thePathURL, true); CFRelease( thePathURL ); thePathURL = NULL; if (theConfig != NULL) { theService = (CFMutableDictionaryRef)CFDictionaryGetValue(theConfig, CFSTR(kPOPConfigKey)); // look for the pop config if (theService == NULL) { keys[0] = CFSTR(kPOPPrincipalKey); values[0] = inPrincipal; theService = (CFMutableDictionaryRef)CFDictionaryCreate(NULL, keys, values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(theConfig, CFSTR(kPOPConfigKey), theService); } else { // and add the principal name or overwrite CFDictionarySetValue(theService, CFSTR(kPOPPrincipalKey), inPrincipal); } } else { // else create minimal config dictionary keys[0] = CFSTR(kPOPPrincipalKey); values[0] = inPrincipal; theService = (CFMutableDictionaryRef)CFDictionaryCreate(NULL, keys, values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); keys[0] = CFSTR(kPOPConfigKey); values[0] = theService; theConfig = (CFMutableDictionaryRef)CFDictionaryCreate(NULL, keys, values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } theData = CFPropertyListCreateXMLData(NULL, theConfig); if (theData != NULL) { dataLength = CFDataGetLength(theData); // open - truncate if ((fd = open(kMailConfigPath, O_RDWR | O_CREAT | O_TRUNC, mode)) == -1) { logString = CFStringCreateWithFormat(NULL, NULL, CFSTR("Error writing Mail config file at %s error = %d\n"), kMailConfigPath, errno); theError = MyCFErrorCreate(kCFErrorDomainPOSIX, (CFIndex)errno, logString); if ( logString != NULL ) CFRelease( logString ); } else { write(fd, CFDataGetBytePtr(theData), dataLength); close(fd); } CFRelease(theData); } CFRelease(theConfig); return theError; } /* We don't neeed to HUP the SMTP service */ CFErrorRef SetSMTPPrincipal(CFStringRef inPrincipal) { CFErrorRef theError = NULL; CFMutableDictionaryRef theConfig = NULL; CFMutableDictionaryRef theService = NULL; CFURLRef thePathURL = NULL; CFDataRef theData = NULL; CFStringRef logString = NULL; const void *keys[1]; const void *values[1]; CFIndex dataLength; int fd; mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; // 644 -rw-r--r-- thePathURL = CFURLCreateFromFileSystemRepresentation(NULL, (UInt8 *)kMailConfigPath, strlen(kMailConfigPath), false); // if the config file exists open it & parse it theConfig = (CFMutableDictionaryRef)CreateMyPropertyListFromFile(thePathURL, true); CFRelease( thePathURL ); thePathURL = NULL; if (theConfig != NULL) { theService = (CFMutableDictionaryRef)CFDictionaryGetValue(theConfig, CFSTR(kSMTPConfigKey)); // look for the imap config if (theService == NULL) { keys[0] = CFSTR(kIMAPPrincipalKey); values[0] = inPrincipal; theService = (CFMutableDictionaryRef)CFDictionaryCreate(NULL, keys, values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(theConfig, CFSTR(kSMTPConfigKey), theService); } else { // and add the principal name or overwrite CFDictionarySetValue(theService, CFSTR(kSMTPPrincipalKey), inPrincipal); } } else { // else create minimal config dictionary keys[0] = CFSTR(kSMTPPrincipalKey); values[0] = inPrincipal; theService = (CFMutableDictionaryRef)CFDictionaryCreate(NULL, keys, values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); keys[0] = CFSTR(kSMTPConfigKey); values[0] = theService; theConfig = (CFMutableDictionaryRef)CFDictionaryCreate(NULL, keys, values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } theData = CFPropertyListCreateXMLData(NULL, theConfig); if (theData != NULL) { dataLength = CFDataGetLength(theData); // open - truncate if ((fd = open(kMailConfigPath, O_RDWR | O_CREAT | O_TRUNC, mode)) == -1) { logString = CFStringCreateWithFormat(NULL, NULL, CFSTR("Error writing Mail config file at %s error = %d\n"), kMailConfigPath, errno); theError = MyCFErrorCreate(kCFErrorDomainPOSIX, (CFIndex)errno, logString); if ( logString != NULL ) CFRelease( logString ); } else { write(fd, CFDataGetBytePtr(theData), dataLength); close(fd); } CFRelease(theData); } CFRelease(theConfig); return theError; } #pragma mark - #pragma mark More Services #pragma mark - // placehloders, there isn't anything to do in order to Kerberize these services CFErrorRef SetSSHPrincipal(CFStringRef inPrincipal) { return NULL; } CFErrorRef SetLDAPPrincipal(CFStringRef inPrincipal) { return NULL; } CFErrorRef SetHTTPPrincipal(CFStringRef inPrincipal) { return NULL; } CFErrorRef SetIPPPrincipal(CFStringRef inPrincipal) { return NULL; } CFErrorRef SetJABBERPrincipal(CFStringRef inPrincipal) { return NULL; } CFErrorRef SetVNCPrincipal(CFStringRef inPrincipal) { return NULL; } CFErrorRef SetPCastPrincipal(CFStringRef inPrincipal) { CFErrorRef theError = NULL; CFMutableDictionaryRef theConfig = NULL; CFURLRef thePathURL = NULL; CFDataRef theData = NULL; CFStringRef logString = NULL; const void *keys[1]; const void *values[1]; CFIndex dataLength; int fd; pid_t serverPid = 0; size_t len; UInt8 theBuffer[16]; mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; // 644 -rw-r--r-- thePathURL = CFURLCreateFromFileSystemRepresentation(NULL, (UInt8 *)kPcastConfigPath, strlen(kPcastConfigPath), false); if ( thePathURL != NULL ) { // if the config file exists open it & parse it theConfig = (CFMutableDictionaryRef) CreateMyPropertyListFromFile(thePathURL, true); CFRelease( thePathURL ); thePathURL = NULL; } if (theConfig != NULL) { // and add the principal name or overwrite CFDictionarySetValue(theConfig, CFSTR(kPcastPrincipalKey), inPrincipal); } else { // else create minimal config dictionary keys[0] = CFSTR(kPcastPrincipalKey); values[0] = inPrincipal; theConfig = (CFMutableDictionaryRef)CFDictionaryCreate(NULL, keys, values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } theData = CFPropertyListCreateXMLData(NULL, theConfig); if (theData != NULL) { dataLength = CFDataGetLength(theData); // open - truncate int err = 0; struct stat sb; if ( lstat("/var/pcast", &sb) != 0 ) err = pwsf_mkdir_p( "/var/pcast", 0755 ); if(err == 0) { if ( lstat("/var/pcast/server", &sb) != 0 ) err = pwsf_mkdir_p( "/var/pcast/server", 0755 ); if(err == 0) { if ((fd = open(kPcastConfigPath, O_RDWR | O_CREAT | O_TRUNC, mode)) == -1) { logString = CFStringCreateWithFormat(NULL, NULL, CFSTR("Error opening Pcast config file at %s error = %d\n"), kPcastConfigPath, errno); theError = MyCFErrorCreate(kCFErrorDomainPOSIX, (CFIndex)errno, logString); if ( logString != NULL ) CFRelease( logString ); } else { len = write(fd, CFDataGetBytePtr(theData), dataLength); if(len != dataLength) { logString = CFStringCreateWithFormat(NULL, NULL, CFSTR("Error writing Pcast config file at %s error = %d\n"), kPcastConfigPath, errno); theError = MyCFErrorCreate(kCFErrorDomainPOSIX, (CFIndex)errno, logString); if ( logString != NULL ) CFRelease( logString ); } close(fd); } } else { logString = CFStringCreateWithFormat(NULL, NULL, CFSTR("Error creating Pcast config directory at /var/pcast/server error = %d\n") ,errno); theError = MyCFErrorCreate(kCFErrorDomainPOSIX, (CFIndex)errno, logString); if ( logString != NULL ) CFRelease( logString ); } } else { logString = CFStringCreateWithFormat(NULL, NULL, CFSTR("Error creating Pcast config directory at /var/pcast error = %d\n") ,errno); theError = MyCFErrorCreate(kCFErrorDomainPOSIX, (CFIndex)errno, logString); if ( logString != NULL ) CFRelease( logString ); } CFRelease(theData); } CFRelease(theConfig); return theError; } CFErrorRef SetFCSvrPrincipal(CFStringRef inPrincipal) { return NULL; } /* SetVPNPrincipal() fd = open the file create (mode 644) if it does not exist if file length is 0 workingConfig = CreateVPNDefaults() else workingConfig = Create Dictionary from fd (mutable) Navigate within the file to /Servers/com.apple.ppp.l2tp/ create EAP dictionary if needed add KerberosServicePrincipalName key write out the new workingConfig close file */ CFErrorRef SetVPNPrincipal(CFStringRef inPrincipal) { CFMutableDictionaryRef workingDict = NULL; CFMutableDictionaryRef tmpDict1 = NULL; CFMutableDictionaryRef tmpDict2 = NULL; CFMutableDictionaryRef tmpDict3 = NULL; CFMutableDictionaryRef tmpDict4 = NULL; CFMutableDictionaryRef tmpDict5 = NULL; CFDataRef theData = NULL; CFErrorRef theError = NULL; CFStringRef logString = NULL; int theConfigFile; CFIndex dataLength = 0; mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; // 644 -rw-r--r-- struct stat fileInfo; bool releaseTmpDict = false; theConfigFile = open(kVPNConfigPath, O_CREAT | O_EXLOCK | O_RDWR, mode); if (theConfigFile == -1) { logString = CFStringCreateWithFormat(NULL, NULL, CFSTR("SetVPNPrincipal: could not open/create %s errno = %d\n"), kVPNConfigPath, errno); theError = MyCFErrorCreate(kCFErrorDomainPOSIX, (CFIndex)errno, logString); if ( logString != NULL ) CFRelease( logString ); return theError; } if (fstat(theConfigFile, &fileInfo) == -1) { logString = CFStringCreateWithFormat(NULL, NULL, CFSTR("SetVPNPrincipal: could not stat %s errno = %d\n"), kVPNConfigPath, errno); theError = MyCFErrorCreate(kCFErrorDomainPOSIX, (CFIndex)errno, logString); if ( logString != NULL ) CFRelease( logString ); close(theConfigFile); // would reset errno return theError; } // could complain here if the file was not a regular file (check fileInfo.st_mode) if (fileInfo.st_size == 0) // we just created the file or it is empty and we can stomp on it { workingDict = CreateVPNDefaults(); } else { workingDict = CreateDictionaryFromFD(theConfigFile, true); } if (workingDict == NULL) { logString = CFStringCreateWithFormat(NULL, NULL, CFSTR("SetVPNPrincipal: File is not a recognizable config file %s\n"), kVPNConfigPath, EINVAL); theError = MyCFErrorCreate(kCFErrorDomainPOSIX, (CFIndex)EINVAL, logString); if ( logString != NULL ) CFRelease( logString ); close(theConfigFile); return theError; } // add the key tmpDict1 = (CFMutableDictionaryRef)CFDictionaryGetValue(workingDict, CFSTR(kVPNServerKey)); if (tmpDict1 == NULL) { logString = CFStringCreateWithFormat(NULL, NULL, CFSTR("SetVPNPrincipal: File is not a recognizable config file %s\n"), kVPNConfigPath, EINVAL); theError = MyCFErrorCreate(kCFErrorDomainPOSIX, (CFIndex)EINVAL, logString); if ( logString != NULL ) CFRelease( logString ); close(theConfigFile); CFRelease(workingDict); return theError; } //l2tp tmpDict2 = (CFMutableDictionaryRef)CFDictionaryGetValue(tmpDict1, CFSTR(kVPNServiceKey)); if (tmpDict2 == NULL) { logString = CFStringCreateWithFormat(NULL, NULL, CFSTR("SetVPNPrincipal: File is not a recognizable config file %s\n"), kVPNConfigPath, EINVAL); theError = MyCFErrorCreate(kCFErrorDomainPOSIX, (CFIndex)EINVAL, logString); if ( logString != NULL ) CFRelease( logString ); close(theConfigFile); CFRelease(workingDict); return theError; } tmpDict3 = (CFMutableDictionaryRef)CFDictionaryGetValue(tmpDict2, CFSTR(kVPNEAPKey)); if (tmpDict3 == NULL) // the EAP directory does not exist, create it { tmpDict3 = CFDictionaryCreateMutable(NULL, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionaryAddValue(tmpDict2, CFSTR(kVPNEAPKey), tmpDict3); releaseTmpDict = true; } CFDictionarySetValue(tmpDict3, CFSTR(kVPNPrincipalKey), inPrincipal); // only release tmpDict3 if it was created here. if (releaseTmpDict) { CFRelease(tmpDict3); // retained in tmpDict2 } //pptp tmpDict4 = (CFMutableDictionaryRef)CFDictionaryGetValue(tmpDict1, CFSTR(kVPNPPTPServiceKey)); if (tmpDict4 == NULL) { logString = CFStringCreateWithFormat(NULL, NULL, CFSTR("SetVPNPrincipal: File is not a recognizable config file %s\n"), kVPNConfigPath, EINVAL); theError = MyCFErrorCreate(kCFErrorDomainPOSIX, (CFIndex)EINVAL, logString); if ( logString != NULL ) CFRelease( logString ); close(theConfigFile); CFRelease(workingDict); return theError; } releaseTmpDict = false; tmpDict5 = (CFMutableDictionaryRef)CFDictionaryGetValue(tmpDict4, CFSTR(kVPNEAPKey)); if (tmpDict5 == NULL) // the EAP directory does not exist, create it { tmpDict5 = CFDictionaryCreateMutable(NULL, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionaryAddValue(tmpDict4, CFSTR(kVPNEAPKey), tmpDict5); releaseTmpDict = true; } CFDictionarySetValue(tmpDict5, CFSTR(kVPNPrincipalKey), inPrincipal); // only release tmpDict5 if it was created here. if (releaseTmpDict) { CFRelease(tmpDict5); // retained in tmpDict4 } // write out the new plist theData = CFPropertyListCreateXMLData(NULL, workingDict); if (theData != NULL) { dataLength = CFDataGetLength(theData); lseek(theConfigFile, 0, SEEK_SET); // start at the beginning if (write(theConfigFile, CFDataGetBytePtr(theData), dataLength) != dataLength) // didn't write the whole file { logString = CFStringCreateWithFormat(NULL, NULL, CFSTR("SetVPNPrincipal: failed to write %s, errno = %d\n"), kVPNConfigPath, theError); theError = MyCFErrorCreate(kCFErrorDomainPOSIX, (CFIndex)errno, logString); if ( logString != NULL ) CFRelease( logString ); close(theConfigFile); // would reset errno CFRelease(theData); CFRelease(workingDict); return theError; } CFRelease(theData); } else { close(theConfigFile); CFRelease(workingDict); return MyCFErrorCreate(kCFErrorDomainPOSIX, (CFIndex)EIO, NULL); } close(theConfigFile); CFRelease(workingDict); return NULL; } CFErrorRef SetXGridPrincipal(CFStringRef inPrincipal) { CFErrorRef theError = NULL; CFStringRef logString = NULL; UInt8 buffer[1024]; size_t length; int theConfigFile = -1; theError = OpenXGridPrincipalFile(O_CREAT | O_EXLOCK | O_RDWR | O_TRUNC, &theConfigFile); if ( theError == NULL ) { bzero(buffer, sizeof(buffer)); if (CFStringGetCString(inPrincipal, (char *)buffer, sizeof(buffer), kCFStringEncodingUTF8) == false) { theError = MyCFErrorCreate(kCFErrorDomainPOSIX, (CFIndex)EINVAL, CFSTR("SetXGridPrincipal: could not convert the principal name\n")); } else { length = strlen((char *)buffer); if (write(theConfigFile, buffer, length) != (ssize_t)length) { logString = CFStringCreateWithFormat(NULL, NULL, CFSTR("SetXGridPrincipal: failed to write %s, errno = %d\n"), kXGridConfigPath, errno); theError = MyCFErrorCreate(kCFErrorDomainPOSIX, (CFIndex)errno, logString); if ( logString != NULL ) CFRelease( logString ); } } close(theConfigFile); } return theError; } CFErrorRef AddXGridPrincipal(CFStringRef inPrincipal) { CFErrorRef theError = NULL; CFStringRef logString = NULL; UInt8 buffer[1024]; size_t length; int theConfigFile = -1; char linefeed = '\n'; struct stat sb; int err; err = stat(kXGridConfigPath, &sb); if (err != 0) { theError = SetXGridPrincipal(inPrincipal); } else { theError = OpenXGridPrincipalFile(O_CREAT | O_EXLOCK | O_RDWR | O_APPEND, &theConfigFile); if (theError == NULL) { bzero(buffer, sizeof(buffer)); if (CFStringGetCString(inPrincipal, (char *)buffer, sizeof(buffer), kCFStringEncodingUTF8) == false) { theError = MyCFErrorCreate(kCFErrorDomainPOSIX, (CFIndex)EINVAL, CFSTR("SetXGridPrincipal: could not convert the principal name\n")); } else { if (sb.st_size > 0) write(theConfigFile, &linefeed, 1); length = strlen((char *)buffer); if (write(theConfigFile, buffer, length) != (ssize_t)length) { logString = CFStringCreateWithFormat(NULL, NULL, CFSTR("SetXGridPrincipal: failed to write %s, errno = %d\n"), kXGridConfigPath, errno); theError = MyCFErrorCreate(kCFErrorDomainPOSIX, (CFIndex)errno, logString); if ( logString != NULL ) CFRelease( logString ); } } close(theConfigFile); } } return theError; } #pragma mark - #pragma mark Support Functions #pragma mark - /* create a mutable dictionary of the form: { CFString AutoGenerated "krbservicesetup" CFDictionary Servers { CFDictionary com.apple.ppp.l2tp { } } } */ CFMutableDictionaryRef CreateVPNDefaults(void) { CFMutableDictionaryRef tmpDict1 = CFDictionaryCreateMutable(NULL, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFMutableDictionaryRef tmpDict2 = CFDictionaryCreateMutable(NULL, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionaryAddValue(tmpDict1, CFSTR(kVPNServiceKey), tmpDict2); CFDictionaryAddValue(tmpDict1, CFSTR(kVPNPPTPServiceKey), tmpDict2); CFRelease(tmpDict2); tmpDict2 = CFDictionaryCreateMutable(NULL, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionaryAddValue(tmpDict2, CFSTR(kVPNServerKey), tmpDict1); CFRelease(tmpDict1); CFDictionaryAddValue(tmpDict2, CFSTR("AutoGenerated"), CFSTR("krbservicesetup")); return tmpDict2; } /* need to place the principal name into /etc/xgrid/controller/service-principal one principal per line, we will stomp on this file. */ static CFErrorRef OpenXGridPrincipalFile(int openFlags, int *configFileRef) { CFErrorRef theError = NULL; CFStringRef logString = NULL; mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP; // 644 -rw-r----- *configFileRef = open( kXGridConfigPath, openFlags, mode ); if ( *configFileRef == -1 ) { logString = CFStringCreateWithFormat( NULL, NULL, CFSTR("SetXGridPrincipal: could not open/create %s errno = %d\n"), kXGridConfigPath, errno ); theError = MyCFErrorCreate( kCFErrorDomainPOSIX, (CFIndex)errno, logString ); if ( logString != NULL ) CFRelease( logString ); } return theError; } static CFMutableDictionaryRef CreateDictionaryFromFD(int inFd, Boolean inMakeMutable) { struct stat fileInfo; UInt8 *buffer = NULL; CFIndex size; CFMutableDictionaryRef theDictionary = NULL; CFDataRef theData = NULL; off_t savedPos; // find out the size if (fstat(inFd, &fileInfo) == -1) return NULL; size = (CFIndex)fileInfo.st_size; // malloc the buffer buffer = (UInt8 *)calloc(1,size); // read the file savedPos = lseek(inFd, 0, SEEK_SET); if (read(inFd, buffer, size) != size) { free((void *)buffer); lseek(inFd, savedPos, SEEK_SET); return NULL; } lseek(inFd, savedPos, SEEK_SET); // make a CFData theData = CFDataCreate (NULL, buffer, size); free((void *)buffer); if (theData == NULL) return NULL; // make the dictionary if (inMakeMutable == true) { theDictionary = (CFMutableDictionaryRef)CFPropertyListCreateFromXMLData (NULL, theData, kCFPropertyListMutableContainersAndLeaves, NULL); } else { theDictionary = (CFMutableDictionaryRef)CFPropertyListCreateFromXMLData (NULL, theData, kCFPropertyListImmutable, NULL); } CFRelease(theData); return theDictionary; } static CFDictionaryRef CreateMyPropertyListFromFile( CFURLRef fileURL, Boolean isMutable ) { CFPropertyListRef propertyList = NULL; CFStringRef errorString = NULL; CFDataRef resourceData = NULL; Boolean status; SInt32 errorCode; // Read the XML file. status = CFURLCreateDataAndPropertiesFromResource( kCFAllocatorDefault, fileURL, &resourceData, // place to put file data NULL, NULL, &errorCode); if(resourceData != NULL) { // Reconstitute the dictionary using the XML data. if (isMutable == true) { propertyList = CFPropertyListCreateFromXMLData( kCFAllocatorDefault, resourceData, kCFPropertyListMutableContainersAndLeaves, &errorString); } else { propertyList = CFPropertyListCreateFromXMLData( kCFAllocatorDefault, resourceData, kCFPropertyListImmutable, &errorString); } CFRelease( resourceData ); } return (CFDictionaryRef)propertyList; } static CFErrorRef MyCFErrorCreate(CFStringRef domain, CFIndex code, CFStringRef description) { CFErrorRef theError = NULL; CFDictionaryRef logDict = NULL; if ( description != NULL ) { logDict = CFDictionaryCreate(NULL, (CFTypeRef *)&kCFErrorLocalizedDescriptionKey, (CFTypeRef *)&description, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } theError = CFErrorCreate(NULL, domain, code, logDict); if ( logDict != NULL ) CFRelease( logDict ); return theError; }