bool os_initialize( adobe::application_t* theApp ) { // // On the Mac we need to install the application menus, respond // to AppleEvents and set the resource path. We set the resource // path first. // ProcessSerialNumber psn; ADOBE_REQUIRE_STATUS( GetCurrentProcess( &psn ) ); FSRef location; ADOBE_REQUIRE_STATUS( GetProcessBundleLocation( &psn, &location ) ); theApp->set_resource_directory( fsref_to_path( location ) / "Contents" / "Resources" ); // // Now load our bundle, sign up for AppleEvents and show the menu. // CFBundleRef bundle = CFBundleGetMainBundle(); IBNibRef nibs = 0; if( !bundle ) return false; ADOBE_REQUIRE_STATUS( CreateNibReferenceWithCFBundle( bundle, kMainNibFileName, &nibs ) ); if( !nibs ) { ::CFRelease( bundle ); return false; } // // Sign up to handle the "Open" AppleEvent. // static adobe::auto_resource<AEEventHandlerUPP> ae_handler( NewAEEventHandlerUPP( handle_open ) ); AEInstallEventHandler( kCoreEventClass, kAEOpenDocuments, ae_handler.get(), 0, false ); // // Install the menu, and it's event handler. // ADOBE_REQUIRE_STATUS( SetMenuBarFromNib( nibs, kMenuBarNibName ) ); static EventTypeSpec hi_event = { kEventClassCommand, kHICommandFromMenu }; static adobe::auto_resource<EventHandlerUPP> hi_handler( NewEventHandlerUPP( menu_command ) ); InstallApplicationEventHandler( hi_handler.get(), 1, &hi_event, theApp, 0 ); // // Register this app as an Appearance Client // // Apple docs: "This function does nothing on Mac OS X. Do not call it." // // RegisterAppearanceClient(); return true; }
CFURLRef copyCurrentProcessURL(void) { ProcessSerialNumber psn = { 0, kCurrentProcess }; FSRef fsref; CFURLRef URL = NULL; OSStatus err = GetProcessBundleLocation(&psn, &fsref); if (err != noErr) { NSLog(CFSTR("in copyCurrentProcessURL in CFGrowlAdditions: Could not get application location, because GetProcessBundleLocation returned %li\n"), (long)err); } else { URL = CFURLCreateFromFSRef(kCFAllocatorDefault, &fsref); } return URL; }
char *get_exename(char *buf, size_t size) { ProcessSerialNumber PSN; FSRef ref; if (GetCurrentProcess(&PSN) < 0 || GetProcessBundleLocation(&PSN, &ref) < 0 || FSRefMakePath(&ref, buf, size) < 0) return NULL; return buf; }
OSErr GetApplicationBundleFSSpec(FSSpecPtr theFSSpecPtr) { OSErr err; ProcessSerialNumber psn; err = GetCurrentProcess(&psn); if (err != noErr) return err; FSRef location; err = GetProcessBundleLocation(&psn, &location); if (err != noErr) return err; return FSGetCatalogInfo(&location, kFSCatInfoNone, NULL, NULL, theFSSpecPtr, NULL); }
Plugger::Plugger() { char temp[256]; _searchpath = NULL; addsearchdir(PACKAGE_LIB_DIR); sprintf(temp,"%s/.freej/plugins",getenv("HOME")); addsearchdir(temp); addsearchdir("/usr/lib/FreeFrame"); addsearchdir("/usr/local/lib/FreeFrame"); #ifdef WITH_FREI0R addsearchdir("/usr/lib/frei0r-1"); addsearchdir("/usr/lib64/frei0r-1"); addsearchdir("/usr/local/lib/frei0r-1"); addsearchdir("/opt/local/lib/frei0r-1"); #endif // addsearchdir("/usr/lib/freej"); // addsearchdir("/usr/local/lib/freej"); // addsearchdir("/opt/video/lib/freej"); #ifdef HAVE_DARWIN ProcessSerialNumber psn; GetProcessForPID(getpid(), &psn); FSRef location; GetProcessBundleLocation(&psn, &location); // 238 == 256 - strlen("/Contents/Plugins") - 1 FSRefMakePath(&location, (UInt8 *)temp, 238); strcat(temp, "/Contents/Plugins"); addsearchdir(temp); sprintf(temp, "%s/Library/Application Support/FreeJ", getenv("HOME")); addsearchdir(temp); sprintf(temp, "%s/Library/Application Support/FreeFrame", getenv("HOME")); addsearchdir(temp); addsearchdir("/Library/Application Support/FreeJ"); addsearchdir("/Library/Application Support/FreeFrame"); #endif }
OSStatus FindPIDForWoW(pid_t *pid) { CFURLRef outAppURL; OSErr err; err = LSFindApplicationForInfo(NULL, (CFStringRef)@"com.blizzard.worldofwarcraft", NULL, NULL, &outAppURL); err = 0; FSRef desired, found; ProcessSerialNumber psn = {0, kNoProcess}; if (!CFURLGetFSRef(outAppURL, &desired)) return errFSBadFSRef; do { err = GetNextProcess(&psn); if (err) return err; // -600 = process not found err = GetProcessBundleLocation(&psn, &found); } while (err || FSCompareFSRefs(&desired, &found)); err = GetProcessPID(&psn, pid); if (err) return err; return noErr; }
//--------------------------------------------------------------------------------------------- int main() { static const EventTypeSpec sApplicationEvents[] = {{ kEventClassCommand, kEventCommandProcess }}; OSErr err; if (!SystemVersionRequired(0x1020)) { DialogRef theAlert; CreateStandardAlert(kAlertStopAlert, CFSTR("Need 10.2 or later!"), NULL, NULL, &theAlert); RunStandardAlert(theAlert, NULL, NULL); return 0; } ProcessSerialNumber psn = {0, kCurrentProcess}; err = GetProcessBundleLocation(&psn, &gApplicationBundleFSRef); err = CreateNibReference(CFSTR("CarbonSketch"), &gOurNibRef ); require_noerr( err, CantGetNibRef ); err = SetMenuBarFromNib( gOurNibRef, CFSTR("MenuBar") ); require_noerr( err, SetMenuBarFromNib_FAILED ); AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, DoOpenApp, 0, false); AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, DoOpenDocuments, 0, false); // AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments, DoPrintDocuments, 0, false); InstallApplicationEventHandler( NewEventHandlerUPP(AppEventHandlerProc), GetEventTypeCount(sApplicationEvents), sApplicationEvents, 0, NULL ); RunApplicationEventLoop(); SetMenuBarFromNib_FAILED: DisposeNibReference(gOurNibRef); CantGetNibRef: return err; }
static PyObject *AE_PSNDescForApplicationPath(PyObject* self, PyObject* args) { ProcessSerialNumber psn = {0, kNoProcess}; FSRef appRef, foundRef; AEDesc result; OSStatus err; if (!PyArg_ParseTuple(args, "O&", AE_GetFSRef, &appRef)) return NULL; while (1) { err = GetNextProcess(&psn); if (err) return AE_MacOSError(err); err = GetProcessBundleLocation(&psn, &foundRef); if (err == noErr && FSCompareFSRefs(&appRef, &foundRef) == noErr) break; } err = AECreateDesc(typeProcessSerialNumber, &psn, sizeof(psn), &result); if (err != noErr) return AE_MacOSError(err); return Py_BuildValue("O&", AE_AEDesc_New, &result); }
// Initialise PhysicsFS, set up basic search paths and add arguments from .ini file. // The .ini file can be in either the user directory or the same directory as the program. // The user directory is searched first. void PHYSFSX_init(int argc, char *argv[]) { #if defined(__unix__) const char *path = NULL; #endif #ifdef macintosh // Mac OS 9 char base_dir[PATH_MAX]; int bundle = 0; #else #define base_dir PHYSFS_getBaseDir() #endif PHYSFS_init(argv[0]); atexit(PHYSFSX_deinit); PHYSFS_permitSymbolicLinks(1); #ifdef macintosh strcpy(base_dir, PHYSFS_getBaseDir()); if (strstr(base_dir, ".app:Contents:MacOSClassic")) // the Mac OS 9 program is still in the .app bundle { char *p; bundle = 1; if (base_dir[strlen(base_dir) - 1] == ':') base_dir[strlen(base_dir) - 1] = '\0'; p = strrchr(base_dir, ':'); *p = '\0'; // path to 'Contents' p = strrchr(base_dir, ':'); *p = '\0'; // path to bundle p = strrchr(base_dir, ':'); *p = '\0'; // path to directory containing bundle } #endif #if (defined(__APPLE__) && defined(__MACH__)) // others? chdir(base_dir); // make sure relative hogdir paths work #endif #if defined(__unix__) char fullPath[PATH_MAX + 5]; # if !(defined(__APPLE__) && defined(__MACH__)) path = "~/.d2x-rebirth/"; # else path = "~/Library/Preferences/D2X Rebirth/"; # endif if (path[0] == '~') // yes, this tilde can be put before non-unix paths. { const char *home = PHYSFS_getUserDir(); strcpy(fullPath, home); // prepend home to the path path++; if (*path == *PHYSFS_getDirSeparator()) path++; strncat(fullPath, path, PATH_MAX + 5 - strlen(home)); } else strncpy(fullPath, path, PATH_MAX + 5); PHYSFS_setWriteDir(fullPath); if (!PHYSFS_getWriteDir()) { // need to make it char *p; char ancestor[PATH_MAX + 5]; // the directory which actually exists char child[PATH_MAX + 5]; // the directory relative to the above we're trying to make strcpy(ancestor, fullPath); while (!PHYSFS_getWriteDir() && ((p = strrchr(ancestor, *PHYSFS_getDirSeparator())))) { if (p[1] == 0) { // separator at the end (intended here, for safety) *p = 0; // kill this separator if (!((p = strrchr(ancestor, *PHYSFS_getDirSeparator())))) break; // give up, this is (usually) the root directory } p[1] = 0; // go to parent PHYSFS_setWriteDir(ancestor); } strcpy(child, fullPath + strlen(ancestor)); for (p = child; (p = strchr(p, *PHYSFS_getDirSeparator())); p++) *p = '/'; PHYSFS_mkdir(child); PHYSFS_setWriteDir(fullPath); } PHYSFS_addToSearchPath(PHYSFS_getWriteDir(), 1); #endif PHYSFS_addToSearchPath(base_dir, 1); InitArgs( argc,argv ); PHYSFS_removeFromSearchPath(base_dir); if (!PHYSFS_getWriteDir()) { PHYSFS_setWriteDir(base_dir); if (!PHYSFS_getWriteDir()) Error("can't set write dir: %s\n", PHYSFS_getLastError()); else PHYSFS_addToSearchPath(PHYSFS_getWriteDir(), 0); } //tell PHYSFS where hogdir is if (GameArg.SysHogDir) PHYSFS_addToSearchPath(GameArg.SysHogDir,1); #if defined(__unix__) else if (!GameArg.SysNoHogDir) PHYSFS_addToSearchPath(SHAREPATH, 1); #endif PHYSFSX_addRelToSearchPath("data", 1); // 'Data' subdirectory // For Macintosh, add the 'Resources' directory in the .app bundle to the searchpaths #if defined(__APPLE__) && defined(__MACH__) { ProcessSerialNumber psn = { 0, kCurrentProcess }; FSRef fsref; OSStatus err; err = GetProcessBundleLocation(&psn, &fsref); if (err == noErr) err = FSRefMakePath(&fsref, (ubyte *)fullPath, PATH_MAX); if (err == noErr) { strncat(fullPath, "/Contents/Resources/", PATH_MAX + 4 - strlen(fullPath)); fullPath[PATH_MAX + 4] = '\0'; PHYSFS_addToSearchPath(fullPath, 1); } } #elif defined(macintosh) if (bundle) { base_dir[strlen(base_dir)] = ':'; // go back in the bundle base_dir[strlen(base_dir)] = ':'; // go back in 'Contents' strncat(base_dir, ":Resources:", PATH_MAX - 1 - strlen(base_dir)); base_dir[PATH_MAX - 1] = '\0'; PHYSFS_addToSearchPath(base_dir, 1); } #endif }
void *updatethreadproc(void*) { char tempDir[PATH_MAX] = ""; /* Flawfinder: ignore */ FSRef tempDirRef; char temp[PATH_MAX] = ""; /* Flawfinder: ignore */ // *NOTE: This buffer length is used in a scanf() below. char deviceNode[1024] = ""; /* Flawfinder: ignore */ LLFILE *downloadFile = NULL; OSStatus err; ProcessSerialNumber psn; char target[PATH_MAX] = ""; /* Flawfinder: ignore */ FSRef targetRef; FSRef targetParentRef; FSVolumeRefNum targetVol; FSRef trashFolderRef; Boolean replacingTarget = false; memset(&tempDirRef, 0, sizeof(tempDirRef)); memset(&targetRef, 0, sizeof(targetRef)); memset(&targetParentRef, 0, sizeof(targetParentRef)); try { // Attempt to get a reference to the Second Life application bundle containing this updater. // Any failures during this process will cause us to default to updating /Applications/Second Life.app { FSRef myBundle; err = GetCurrentProcess(&psn); if(err == noErr) { err = GetProcessBundleLocation(&psn, &myBundle); } if(err == noErr) { // Sanity check: Make sure the name of the item referenced by targetRef is "Second Life.app". FSRefMakePath(&myBundle, (UInt8*)target, sizeof(target)); llinfos << "Updater bundle location: " << target << llendl; } // Our bundle should be in Second Life.app/Contents/Resources/AutoUpdater.app // so we need to go up 3 levels to get the path to the main application bundle. if(err == noErr) { err = FSGetCatalogInfo(&myBundle, kFSCatInfoNone, NULL, NULL, NULL, &targetRef); } if(err == noErr) { err = FSGetCatalogInfo(&targetRef, kFSCatInfoNone, NULL, NULL, NULL, &targetRef); } if(err == noErr) { err = FSGetCatalogInfo(&targetRef, kFSCatInfoNone, NULL, NULL, NULL, &targetRef); } // And once more to get the parent of the target if(err == noErr) { err = FSGetCatalogInfo(&targetRef, kFSCatInfoNone, NULL, NULL, NULL, &targetParentRef); } if(err == noErr) { FSRefMakePath(&targetRef, (UInt8*)target, sizeof(target)); llinfos << "Path to target: " << target << llendl; } // Sanity check: make sure the target is a bundle with the right identifier if(err == noErr) { // Assume the worst... err = -1; if(isFSRefViewerBundle(&targetRef)) { // This is the bundle we're looking for. err = noErr; replacingTarget = true; } } // Make sure the target's parent directory is writable. if(err == noErr) { if(!isDirWritable(targetParentRef)) { // Parent directory isn't writable. llinfos << "Target parent directory not writable." << llendl; err = -1; replacingTarget = false; } } if(err != noErr) { Boolean isDirectory; llinfos << "Target search failed, defaulting to /Applications/" << gProductName << ".app." << llendl; // Set up the parent directory err = FSPathMakeRef((UInt8*)"/Applications", &targetParentRef, &isDirectory); if((err != noErr) || (!isDirectory)) { // We're so hosed. llinfos << "Applications directory not found, giving up." << llendl; throw 0; } snprintf(target, sizeof(target), "/Applications/%s.app", gProductName); memset(&targetRef, 0, sizeof(targetRef)); err = FSPathMakeRef((UInt8*)target, &targetRef, NULL); if(err == fnfErr) { // This is fine, just means we're not replacing anything. err = noErr; replacingTarget = false; } else { replacingTarget = true; } // Make sure the target's parent directory is writable. if(err == noErr) { if(!isDirWritable(targetParentRef)) { // Parent directory isn't writable. llinfos << "Target parent directory not writable." << llendl; err = -1; replacingTarget = false; } } } // If we haven't fixed all problems by this point, just bail. if(err != noErr) { llinfos << "Unable to pick a target, giving up." << llendl; throw 0; } } // Find the volID of the volume the target resides on { FSCatalogInfo info; err = FSGetCatalogInfo( &targetParentRef, kFSCatInfoVolume, &info, NULL, NULL, NULL); if(err != noErr) throw 0; targetVol = info.volume; } // Find the temporary items and trash folders on that volume. err = FSFindFolder( targetVol, kTrashFolderType, true, &trashFolderRef); if(err != noErr) throw 0; #if 0 // *HACK for DEV-11935 see below for details. FSRef tempFolderRef; err = FSFindFolder( targetVol, kTemporaryFolderType, true, &tempFolderRef); if(err != noErr) throw 0; err = FSRefMakePath(&tempFolderRef, (UInt8*)temp, sizeof(temp)); if(err != noErr) throw 0; #else // *HACK for DEV-11935 the above kTemporaryFolderType query was giving // back results with path names that seem to be too long to be used as // mount points. I suspect this incompatibility was introduced in the // Leopard 10.5.2 update, but I have not verified this. char const HARDCODED_TMP[] = "/tmp"; strncpy(temp, HARDCODED_TMP, sizeof(HARDCODED_TMP)); #endif // 0 *HACK for DEV-11935 // Skip downloading the file if the dmg was passed on the command line. std::string dmgName; if(gDmgFile != NULL) { dmgName = basename((char *)gDmgFile); char * dmgDir = dirname((char *)gDmgFile); strncpy(tempDir, dmgDir, sizeof(tempDir)); err = FSPathMakeRef((UInt8*)tempDir, &tempDirRef, NULL); if(err != noErr) throw 0; chdir(tempDir); goto begin_install; } else { // Continue on to download file. dmgName = "SecondLife.dmg"; } strncat(temp, "/SecondLifeUpdate_XXXXXX", (sizeof(temp) - strlen(temp)) - 1); if(mkdtemp(temp) == NULL) { throw 0; } strncpy(tempDir, temp, sizeof(tempDir)); temp[sizeof(tempDir) - 1] = '\0'; llinfos << "tempDir is " << tempDir << llendl; err = FSPathMakeRef((UInt8*)tempDir, &tempDirRef, NULL); if(err != noErr) throw 0; chdir(tempDir); snprintf(temp, sizeof(temp), "SecondLife.dmg"); downloadFile = LLFile::fopen(temp, "wb"); /* Flawfinder: ignore */ if(downloadFile == NULL) { throw 0; } { CURL *curl = curl_easy_init(); curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); // curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &curl_download_callback); curl_easy_setopt(curl, CURLOPT_FILE, downloadFile); curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0); curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, &curl_progress_callback_func); curl_easy_setopt(curl, CURLOPT_URL, gUpdateURL); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); sendProgress(0, 1, CFSTR("Downloading...")); CURLcode result = curl_easy_perform(curl); curl_easy_cleanup(curl); if(gCancelled) { llinfos << "User cancel, bailing out."<< llendl; throw 0; } if(result != CURLE_OK) { llinfos << "Error " << result << " while downloading disk image."<< llendl; throw 0; } fclose(downloadFile); downloadFile = NULL; } begin_install: sendProgress(0, 0, CFSTR("Mounting image...")); LLFile::mkdir("mnt", 0700); // NOTE: we could add -private at the end of this command line to keep the image from showing up in the Finder, // but if our cleanup fails, this makes it much harder for the user to unmount the image. std::string mountOutput; boost::format cmdFormat("hdiutil attach %s -mountpoint mnt"); cmdFormat % dmgName; FILE* mounter = popen(cmdFormat.str().c_str(), "r"); /* Flawfinder: ignore */ if(mounter == NULL) { llinfos << "Failed to mount disk image, exiting."<< llendl; throw 0; } // We need to scan the output from hdiutil to find the device node it uses to attach the disk image. // If we don't have this information, we can't detach it later. while(mounter != NULL) { size_t len = fread(temp, 1, sizeof(temp)-1, mounter); temp[len] = 0; mountOutput.append(temp); if(len < sizeof(temp)-1) { // End of file or error. int result = pclose(mounter); if(result != 0) { // NOTE: We used to abort here, but pclose() started returning // -1, possibly when the size of the DMG passed a certain point llinfos << "Unexpected result closing pipe: " << result << llendl; } mounter = NULL; } } if(!mountOutput.empty()) { const char *s = mountOutput.c_str(); const char *prefix = "/dev/"; char *sub = strstr(s, prefix); if(sub != NULL) { sub += strlen(prefix); /* Flawfinder: ignore */ sscanf(sub, "%1023s", deviceNode); /* Flawfinder: ignore */ } } if(deviceNode[0] != 0) { llinfos << "Disk image attached on /dev/" << deviceNode << llendl; } else { llinfos << "Disk image device node not found!" << llendl; throw 0; } // Get an FSRef to the new application on the disk image FSRef sourceRef; FSRef mountRef; snprintf(temp, sizeof(temp), "%s/mnt", tempDir); llinfos << "Disk image mount point is: " << temp << llendl; err = FSPathMakeRef((UInt8 *)temp, &mountRef, NULL); if(err != noErr) { llinfos << "Couldn't make FSRef to disk image mount point." << llendl; throw 0; } sendProgress(0, 0, CFSTR("Searching for the app bundle...")); err = findAppBundleOnDiskImage(&mountRef, &sourceRef); if(err != noErr) { llinfos << "Couldn't find application bundle on mounted disk image." << llendl; throw 0; } else { llinfos << "found the bundle." << llendl; } sendProgress(0, 0, CFSTR("Preparing to copy files...")); FSRef asideRef; char aside[MAX_PATH]; /* Flawfinder: ignore */ // this will hold the name of the destination target CFStringRef appNameRef; if(replacingTarget) { // Get the name of the target we're replacing HFSUniStr255 appNameUniStr; err = FSGetCatalogInfo(&targetRef, 0, NULL, &appNameUniStr, NULL, NULL); if(err != noErr) throw 0; appNameRef = FSCreateStringFromHFSUniStr(NULL, &appNameUniStr); // Move aside old version (into work directory) err = FSMoveObject(&targetRef, &tempDirRef, &asideRef); if(err != noErr) { llwarns << "failed to move aside old version (error code " << err << ")" << llendl; throw 0; } // Grab the path for later use. err = FSRefMakePath(&asideRef, (UInt8*)aside, sizeof(aside)); } else { // Construct the name of the target based on the product name char appName[MAX_PATH]; /* Flawfinder: ignore */ snprintf(appName, sizeof(appName), "%s.app", gProductName); appNameRef = CFStringCreateWithCString(NULL, appName, kCFStringEncodingUTF8); } sendProgress(0, 0, CFSTR("Copying files...")); llinfos << "Starting copy..." << llendl; // Copy the new version from the disk image to the target location. err = FSCopyObjectSync( &sourceRef, &targetParentRef, appNameRef, &targetRef, kFSFileOperationDefaultOptions); // Grab the path for later use. err = FSRefMakePath(&targetRef, (UInt8*)target, sizeof(target)); if(err != noErr) throw 0; llinfos << "Copy complete. Target = " << target << llendl; if(err != noErr) { // Something went wrong during the copy. Attempt to put the old version back and bail. (void)FSDeleteObject(&targetRef); if(replacingTarget) { (void)FSMoveObject(&asideRef, &targetParentRef, NULL); } throw 0; } else { // The update has succeeded. Clear the cache directory. sendProgress(0, 0, CFSTR("Clearing cache...")); llinfos << "Clearing cache..." << llendl; char mask[LL_MAX_PATH]; /* Flawfinder: ignore */ snprintf(mask, LL_MAX_PATH, "%s*.*", gDirUtilp->getDirDelimiter().c_str()); gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""),mask); llinfos << "Clear complete." << llendl; } } catch(...) { if(!gCancelled) if(gFailure == noErr) gFailure = -1; } // Failures from here on out are all non-fatal and not reported. sendProgress(0, 3, CFSTR("Cleaning up...")); // Close disk image file if necessary if(downloadFile != NULL) { llinfos << "Closing download file." << llendl; fclose(downloadFile); downloadFile = NULL; } sendProgress(1, 3); // Unmount image if(deviceNode[0] != 0) { llinfos << "Detaching disk image." << llendl; snprintf(temp, sizeof(temp), "hdiutil detach '%s'", deviceNode); system(temp); /* Flawfinder: ignore */ } sendProgress(2, 3); // Move work directory to the trash if(tempDir[0] != 0) { // chdir("/"); // FSDeleteObjects(tempDirRef); llinfos << "Moving work directory to the trash." << llendl; err = FSMoveObject(&tempDirRef, &trashFolderRef, NULL); if(err != noErr) { llwarns << "failed to move files to trash, (error code " << err << ")" << llendl; } // snprintf(temp, sizeof(temp), "rm -rf '%s'", tempDir); // printf("%s\n", temp); // system(temp); } if(!gCancelled && !gFailure && (target[0] != 0)) { llinfos << "Touching application bundle." << llendl; snprintf(temp, sizeof(temp), "touch '%s'", target); system(temp); /* Flawfinder: ignore */ llinfos << "Launching updated application." << llendl; snprintf(temp, sizeof(temp), "open '%s'", target); system(temp); /* Flawfinder: ignore */ } sendDone(); return(NULL); }
bool CBOINCClientManager::StartupBOINCCore() { wxLogTrace(wxT("Function Start/End"), wxT("CMainDocument::StartupBOINCCore - Function Begin")); bool bReturnValue = false; wxString strExecute = wxEmptyString; if (IsBOINCCoreRunning()) return true; #if defined(__WXMSW__) LPTSTR szExecute = NULL; LPTSTR szDataDirectory = NULL; if (IsBOINCConfiguredAsDaemon()) { return (!!StartBOINCService()); } // Append synecd.exe to the end of the strExecute string strExecute.Printf( wxT("\"%ssynecd.exe\" --redirectio --launched_by_manager %s"), wxGetApp().GetRootDirectory().c_str(), wxGetApp().GetArguments().c_str() ); PROCESS_INFORMATION pi; STARTUPINFO si; BOOL bProcessStarted; memset(&pi, 0, sizeof(pi)); memset(&si, 0, sizeof(si)); si.cb = sizeof(si); si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; szExecute = (LPTSTR)strExecute.c_str(); if (wxGetApp().GetDataDirectory().empty()) { szDataDirectory = NULL; } else { szDataDirectory = (LPTSTR)wxGetApp().GetDataDirectory().c_str(); } wxLogTrace(wxT("Function Status"), wxT("CMainDocument::StartupBOINCCore - szExecute '%s'\n"), szExecute); wxLogTrace(wxT("Function Status"), wxT("CMainDocument::StartupBOINCCore - szDataDirectory '%s'\n"), szDataDirectory); bProcessStarted = CreateProcess( NULL, szExecute, NULL, NULL, FALSE, CREATE_NEW_PROCESS_GROUP|CREATE_NO_WINDOW, NULL, szDataDirectory, &si, &pi ); if (bProcessStarted) { m_lBOINCCoreProcessId = pi.dwProcessId; m_hBOINCCoreProcess = pi.hProcess; } #elif defined(__WXMAC__) char buf[1024]; char *argv[5]; ProcessSerialNumber ourPSN; FSRef ourFSRef; OSErr err; if (IsBOINCConfiguredAsDaemon() == NewStyleDaemon) { system ("launchctl load /Library/LaunchDaemons/com.googlecode.synecdoche.plist"); system ("launchctl start com.googleccode.synecdoche"); bReturnValue = IsBOINCCoreRunning(); } else { // Get the full path to core client inside this application's bundle err = GetCurrentProcess (&ourPSN); if (err == noErr) { err = GetProcessBundleLocation(&ourPSN, &ourFSRef); } if (err == noErr) { err = FSRefMakePath (&ourFSRef, (UInt8*)buf, sizeof(buf)); } if (err == noErr) { #if 0 // The Mac version of wxExecute(wxString& ...) crashes if there is a space in the path strExecute = wxT("\""); strExecute += wxT(buf); strExecute += wxT("/Contents/Resources/synecd\" --redirectio --launched_by_manager"); m_lBOINCCoreProcessId = ::wxExecute(strExecute); #else // Use wxExecute(wxChar **argv ...) instead of wxExecute(wxString& ...) strcat(buf, "/Contents/Resources/synecd"); argv[0] = buf; argv[1] = "--redirectio"; argv[2] = "--launched_by_manager"; argv[3] = NULL; #ifdef SANDBOX if (!g_use_sandbox) { argv[3] = "--insecure"; argv[4] = NULL; } #endif // Under wxMac-2.8.0, wxExecute starts a separate thread // to wait for child's termination. // That wxProcessTerminationThread uses a huge amount of processor // time (about 11% of one CPU on 2GHz Intel Dual-Core Mac). // m_lBOINCCoreProcessId = ::wxExecute(argv); run_program( "/Library/Application Support/Synecdoche Data", buf, argv[3] ? 4 : 3, argv, 0.0, m_lBOINCCoreProcessId ); #endif } else { buf[0] = '\0'; } } #else // Unix based systems // Append boinc.exe to the end of the strExecute string and get ready to rock strExecute = ::wxGetCwd() + wxT("/boinc --redirectio --launched_by_manager"); #ifdef SANDBOX if (!g_use_sandbox) { strExecute += wxT(" --insecure"); } #endif // SANDBOX wxLogTrace(wxT("Function Status"), wxT("CMainDocument::StartupBOINCCore - szExecute '%s'\n"), strExecute.c_str()); wxLogTrace(wxT("Function Status"), wxT("CMainDocument::StartupBOINCCore - szDataDirectory '%s'\n"), ::wxGetCwd().c_str()); m_lBOINCCoreProcessId = ::wxExecute(strExecute); #endif if (0 != m_lBOINCCoreProcessId) { m_bBOINCStartedByManager = true; bReturnValue = true; // Allow time for daemon to start up so we don't keep relaunching it for (int i = 0; i < 100; ++i) { // Wait up to 4 seconds in 40ms increments if (IsBOINCCoreRunning()) { break; } boinc_sleep(0.04); } } wxLogTrace(wxT("Function Start/End"), wxT("CMainDocument::StartupBOINCCore - Function End")); return bReturnValue; }
static PyObject *AE_AddressDescToPath(PyObject *_self, PyObject *_args) { AEDesc desc; ProcessSerialNumber psn; pid_t pid; OSType creatorType = kLSUnknownCreator; Size cSize; char *cStr; CFStringRef bundleID = NULL; FSRef fsref; UInt8 path[PATH_MAX]; PyObject* pathObj; OSStatus err; if (!PyArg_ParseTuple(_args, "O&", AE_AEDesc_Convert, &desc)) return NULL; switch (desc.descriptorType) { case typeKernelProcessID: err = AEGetDescData(&desc, &pid, sizeof(pid)); if (err) return AE_MacOSError(err); err = GetProcessForPID(pid, &psn); if (err) return AE_MacOSError(err); err = GetProcessBundleLocation(&psn, &fsref); if (err) return AE_MacOSError(err); break; case typeProcessSerialNumber: err = AEGetDescData(&desc, &psn, sizeof(psn)); if (err) return AE_MacOSError(err); err = GetProcessBundleLocation(&psn, &fsref); if (err) return AE_MacOSError(err); break; case typeApplSignature: err = AEGetDescData(&desc, &creatorType, sizeof(creatorType)); if (err) return AE_MacOSError(err); err = LSFindApplicationForInfo(creatorType, bundleID, NULL, &fsref, NULL); if (err) return AE_MacOSError(err); break; case typeApplicationBundleID: cSize = AEGetDescDataSize(&desc); cStr = malloc((size_t)cSize); if (!cStr) return AE_MacOSError(errAECoercionFail); err = AEGetDescData(&desc, cStr, cSize); if (err) return AE_MacOSError(err); bundleID = CFStringCreateWithBytes(NULL, (UInt8 *)cStr, (CFIndex)cSize, kCFStringEncodingUTF8, 0); free(cStr); if (!bundleID) return AE_MacOSError(errAECoercionFail); err = LSFindApplicationForInfo(creatorType, bundleID, NULL, &fsref, NULL); if (err) return AE_MacOSError(err); break; case typeMachPort: // unsupported case typeApplicationURL: // unsupported (remote applications) default: return AE_MacOSError(errAECoercionFail); } err = FSRefMakePath(&fsref, path, sizeof(path)); if (err) return AE_MacOSError(err); pathObj = PyUnicode_DecodeUTF8((char *)path, strlen((char *)path), NULL); return Py_BuildValue("O", pathObj); }
// Returns FALSE (0) if owners and permissions are OK, else TRUE (1) int check_security( #ifdef _MAC_INSTALLER char *bundlePath, char *dataPath, #endif int use_sandbox, int isManager, char* path_to_error, int len ) { passwd *pw; group *grp; gid_t egid; uid_t euid; char dir_path[MAXPATHLEN], full_path[MAXPATHLEN]; struct stat sbuf; int retval; int useFakeProjectUserAndGroup = 0; #ifdef __WXMAC__ // If Mac BOINC Manager ProcessSerialNumber ourPSN; ProcessInfoRec pInfo; FSRef ourFSRef; #endif #define NUMBRANDS 3 char *saverName[NUMBRANDS]; saverName[0] = "BOINCSaver"; saverName[1] = "GridRepublic"; saverName[2] = "Progress Thru Processors"; useFakeProjectUserAndGroup = ! use_sandbox; #ifdef _DEBUG #ifdef DEBUG_WITH_FAKE_PROJECT_USER_AND_GROUP useFakeProjectUserAndGroup = 1; #endif #endif // _DEBUG // GDB can't attach to applications which are running as a diferent user or group so // it ignores the S_ISUID and S_ISGID permisison bits when launching an application. // To work around this, and to allow testing the uninstalled Deployment version, we // assume that the BOINC Client has the correct user and group. // We must get the BOINC Client's user and group differently depending on whether we // were called from the Manager or from the Client #ifdef __WXMAC__ // If Mac BOINC Manager // Get the full path to BOINC Manager application's bundle retval = GetCurrentProcess (&ourPSN); if (retval) return -1000; // Should never happen memset(&pInfo, 0, sizeof(pInfo)); pInfo.processInfoLength = sizeof( ProcessInfoRec ); retval = GetProcessInformation(&ourPSN, &pInfo); if (retval) return -1001; // Should never happen retval = GetProcessBundleLocation(&ourPSN, &ourFSRef); if (retval) return -1002; // Should never happen retval = FSRefMakePath (&ourFSRef, (UInt8*)dir_path, sizeof(dir_path)); if (retval) return -1003; // Should never happen #elif defined (_MAC_INSTALLER) strlcpy(dir_path, bundlePath, sizeof(dir_path)); #endif if (use_sandbox) { #if (defined(__WXMAC__) || defined(_MAC_INSTALLER)) // If called from Mac BOINC Manager or installer // Get the full path to BOINC Client inside this application's bundle snprintf(full_path, sizeof(full_path), "%s/Contents/Resources/boinc", dir_path ); #else if (isManager) { // If called from BOINC Manager but not on Mac getcwd(full_path, sizeof(full_path)); // Assume Client is in current directory strlcat(full_path, "/boinc", sizeof(full_path)); } else // If called from BOINC Client GetPathToThisProcess(full_path, sizeof(full_path)); #endif retval = stat(full_path, &sbuf); if (retval) return -1004; // Should never happen if ((sbuf.st_mode & (S_ISUID | S_ISGID)) != (S_ISUID | S_ISGID)) return -1005; boinc_master_uid = sbuf.st_uid; boinc_master_gid = sbuf.st_gid; #ifdef __WXMAC__ if (!IsUserInGroupBM()) return -1099; #endif } else { boinc_master_uid = geteuid(); boinc_master_gid = getegid(); } #ifdef _MAC_INSTALLER // Require absolute owner and group boinc_master:boinc_master strlcpy(boinc_master_user_name, REAL_BOINC_MASTER_NAME, sizeof(boinc_master_user_name)); pw = getpwnam(boinc_master_user_name); if (pw == NULL) return -1006; // User boinc_master does not exist boinc_master_uid = pw->pw_uid; strlcpy(boinc_master_group_name, REAL_BOINC_MASTER_NAME, sizeof(boinc_master_group_name)); grp = getgrnam(boinc_master_group_name); if (grp == NULL) return -1007; // Group boinc_master does not exist boinc_master_gid = grp->gr_gid; #else // Use current user and group (see comment above) pw = getpwuid(boinc_master_uid); if (pw == NULL) return -1008; // Should never happen strlcpy(boinc_master_user_name, pw->pw_name, sizeof(boinc_master_user_name)); grp = getgrgid(boinc_master_gid); if (grp == NULL) return -1009; strlcpy(boinc_master_group_name, grp->gr_name, sizeof(boinc_master_group_name)); #endif if (useFakeProjectUserAndGroup) { // For easier debugging of project applications strlcpy(boinc_project_user_name, boinc_master_user_name, sizeof(boinc_project_user_name)); strlcpy(boinc_project_group_name, boinc_master_group_name, sizeof(boinc_project_group_name)); boinc_project_uid = boinc_master_uid; boinc_project_gid = boinc_master_gid; } else { strlcpy(boinc_project_user_name, REAL_BOINC_PROJECT_NAME, sizeof(boinc_project_user_name)); pw = getpwnam(boinc_project_user_name); if (pw == NULL) return -1010; // User boinc_project does not exist boinc_project_uid = pw->pw_uid; strlcpy(boinc_project_group_name, REAL_BOINC_PROJECT_NAME, sizeof(boinc_project_group_name)); grp = getgrnam(boinc_project_group_name); if (grp == NULL) return -1011; // Group boinc_project does not exist boinc_project_gid = grp->gr_gid; } #if 0 // Manager is no longer setgid #if (defined(__WXMAC__) || defined(_MAC_INSTALLER)) // If Mac BOINC Manager or installer // Get the full path to BOINC Manager executable // inside this application's bundle // snprintf(full_path, sizeof(full_path), "%s/Contents/MacOS/", dir_path); // To allow for branding, assume name of executable inside bundle // is same as name of bundle // p = strrchr(dir_path, '/'); // Assume name of executable inside bundle is same as name of bundle if (p == NULL) p = dir_path - 1; strlcat(full_path, p+1, sizeof(full_path)); p = strrchr(full_path, '.'); // Strip off bundle extension (".app") if (p) *p = '\0'; retval = lstat(full_path, &sbuf); if (retval) return -1013; // Should never happen if (sbuf.st_gid != boinc_master_gid) return -1014; if (use_sandbox) { if ((sbuf.st_mode & S_ISGID) != S_ISGID) return -1015; } #endif #endif // Manager is no longer setgid #ifdef _MAC_INSTALLER // Require absolute owner and group boinc_master:boinc_master // Get the full path to BOINC Client inside this application's bundle // snprintf(full_path, sizeof(full_path), "%s/Contents/Resources/boinc", dir_path ); retval = stat(full_path, &sbuf); if (retval) return -1016; // Should never happen if (sbuf.st_gid != boinc_master_gid) return -1017; if (sbuf.st_uid != boinc_master_uid) return -1018; #endif #if (defined(__WXMAC__) || defined(_MAC_INSTALLER)) // If Mac BOINC Manager or installer // Version 6 screensaver has its own embedded switcher application, but older versions don't. // We don't allow unauthorized users to run the standard switcher application in the BOINC // Data directory because they could use it to run as user & group boinc_project and damage // project files. The screensaver's gfx_switcher application has very limited functionality // to avoid this risk. if (use_sandbox) { for (int i=0; i<NUMBRANDS; i++) { // Does gfx_switcher exist in screensaver bundle? sprintf(full_path, "/Library/Screen Savers/%s.saver/Contents/Resources/gfx_switcher", saverName[i]); retval = stat(full_path, &sbuf); if (! retval) { #ifdef _DEBUG if (sbuf.st_uid != boinc_master_uid) return -1101; if (sbuf.st_gid != boinc_master_gid) return -1102; if ((sbuf.st_mode & (S_ISUID | S_ISGID)) != 0) return -1103; #else if (sbuf.st_uid != 0) return -1101; if (sbuf.st_gid != boinc_master_gid) return -1102; if ((sbuf.st_mode & (S_ISUID | S_ISGID)) != S_ISUID) return -1103; #endif } } } #endif // rgid = getgid(); // ruid = getuid(); egid = getegid(); euid = geteuid(); #ifdef _MAC_INSTALLER strlcpy(dir_path, dataPath, sizeof(dir_path)); // Installer #else // _MAC_INSTALLER getcwd(dir_path, sizeof(dir_path)); // Client or Manager if (! isManager) { // If BOINC Client if (egid != boinc_master_gid) return -1019; // Client should be running setgid boinc_master if (euid != boinc_master_uid) return -1020; // BOINC Client should be running setuid boinc_master } #endif retval = stat(dir_path, &sbuf); if (retval) return -1021; // Should never happen if (use_sandbox) { // The top-level BOINC Data directory can have a different user if created by the Manager, // but it should always have group boinc_master. if (sbuf.st_gid != boinc_master_gid) return -1022; // The top-level BOINC Data directory should have permission 771 or 571 if ((sbuf.st_mode & 0577) != 0571) return -1023; } else { if (sbuf.st_uid != boinc_master_uid) return -1022; } snprintf(full_path, sizeof(full_path), "%s/%s", dir_path, PROJECTS_DIR); retval = stat(full_path, &sbuf); if (!retval) { // Client can create projects directory if it does not yet exist. // if (use_sandbox) { if (sbuf.st_gid != boinc_project_gid) return -1024; if ((sbuf.st_mode & 0777) != 0770) return -1025; } if (sbuf.st_uid != boinc_master_uid) return -1026; // Step through project directories retval = CheckNestedDirectories(full_path, 1, use_sandbox, isManager, path_to_error, len); if (retval) return retval; } snprintf(full_path, sizeof(full_path), "%s/%s", dir_path, SLOTS_DIR); retval = stat(full_path, &sbuf); if (! retval) { // Client can create slots directory if it does not yet exist. if (use_sandbox) { if (sbuf.st_gid != boinc_project_gid) return -1027; if ((sbuf.st_mode & 0777) != 0770) return -1028; } if (sbuf.st_uid != boinc_master_uid) return -1029; // Step through slot directories retval = CheckNestedDirectories(full_path, 1, use_sandbox, isManager, path_to_error, len); if (retval) return retval; } snprintf(full_path, sizeof(full_path), "%s/%s", dir_path, GUI_RPC_PASSWD_FILE ); retval = stat(full_path, &sbuf); if (! retval) { // Client can create RPC password file if it does not yet exist. if (use_sandbox) { if (sbuf.st_gid != boinc_master_gid) return -1030; if ((sbuf.st_mode & 0777) != 0660) return -1032; } else { if ((sbuf.st_mode & 0717) != 0600) return -1032; } if (sbuf.st_uid != boinc_master_uid) return -1031; } if (use_sandbox) { snprintf(full_path, sizeof(full_path), "%s/%s", dir_path, SWITCHER_DIR); retval = stat(full_path, &sbuf); if (retval) return -1033; if (sbuf.st_gid != boinc_master_gid) return -1034; if (sbuf.st_uid != boinc_master_uid) return -1035; if ((sbuf.st_mode & 0777) != 0550) return -1036; strlcat(full_path, "/", sizeof(full_path)); strlcat(full_path, SWITCHER_FILE_NAME, sizeof(full_path)); retval = stat(full_path, &sbuf); if (retval) return -1037; if (sbuf.st_gid != boinc_master_gid) return -1038; if (sbuf.st_uid != 0) // root return -1039; if ((sbuf.st_mode & 07777) != 04050) return -1040; snprintf(full_path, sizeof(full_path), "%s/%s/%s", dir_path, SWITCHER_DIR, SETPROJECTGRP_FILE_NAME ); retval = stat(full_path, &sbuf); if (retval) return -1041; if (sbuf.st_gid != boinc_project_gid) return -1042; if (sbuf.st_uid != boinc_master_uid) return -1043; if ((sbuf.st_mode & 07777) != 02500) return -1044; #ifdef __APPLE__ #if 0 // AppStats is deprecated as of version 5.8.15 strlcat(full_path, "/", sizeof(full_path)); strlcat(full_path, APP_STATS_FILE_NAME, sizeof(full_path)); retval = stat(full_path, &sbuf); if (retval) return -1045; if (sbuf.st_gid != boinc_master_gid) return -1046; if (sbuf.st_uid != 0) // AppStats application must be setuid root return -1047; if ((sbuf.st_mode & 07777) != 04550) return -1048; #endif #endif // __APPLE__ snprintf(full_path, sizeof(full_path), "%s/%s", dir_path, SS_CONFIG_FILE ); retval = stat(full_path, &sbuf); if (!retval) { if (sbuf.st_uid != boinc_master_uid) return -1051; if (sbuf.st_gid != boinc_master_gid) return -1052; if ((sbuf.st_mode & 0777) != 0664) return -1053; } // Screensaver config file ss_config.xml exists } // if (use_sandbox) return 0; }
// Pass NULL for path when calling this routine from within BOINC Manager int SetBOINCAppOwnersGroupsAndPermissions(char *path) { char fullpath[MAXPATHLEN]; char dir_path[MAXPATHLEN]; char buf1[80]; ProcessSerialNumber ourPSN; FSRef ourFSRef, ref; char *p; Boolean isDirectory; OSStatus err = noErr; #define NUMBRANDS 3 char *saverName[NUMBRANDS]; saverName[0] = "BOINCSaver"; saverName[1] = "GridRepublic"; saverName[2] = "Progress Thru Processors"; #ifdef _DEBUG err = SetFakeMasterNames(); if (err) return err; #endif if (path == NULL) { // NULL means we were called from within BOINC Manager // Get the full path to this application's bundle (BOINC Manager's bundle) err = GetCurrentProcess (&ourPSN); if (err) return err; // Should never happen err = GetProcessBundleLocation(&ourPSN, &ourFSRef); if (err) return err; // Should never happen err = FSRefMakePath (&ourFSRef, (UInt8*)dir_path, sizeof(dir_path)); if (err) return err; // Should never happen } else strlcpy(dir_path, path, MAXPATHLEN); // Path to BOINC Manager's bundle was passed as argument if (strlen(fullpath) >= (MAXPATHLEN-1)) { ShowSecurityError("SetBOINCAppOwnersGroupsAndPermissions: path to Manager is too long"); return -1; } strlcpy(fullpath, dir_path, sizeof(fullpath)); #ifdef _DEBUG // chmod -R u=rwx,g=rwx,o=rx path/BOINCManager.app // 0775 = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH // Set read, write permission for user; read and execute permission for group and others err = DoPrivilegedExec(chmodPath, "-R", "u=rwx,g=rwx,o=rx", fullpath, NULL, NULL, NULL); #else // chmod -R u=rx,g=rx,o=rx path/BOINCManager.app // 0555 = S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH // Set read, write permission for user; read and execute permission for group and others err = DoPrivilegedExec(chmodPath, "-R", "u=rx,g=rx,o=rx", fullpath, NULL, NULL, NULL); #endif if (err) return err; // Get the full path to BOINC Manager executable inside this application's bundle strlcat(fullpath, "/Contents/MacOS/", sizeof(fullpath)); // To allow for branding, assume name of executable inside bundle is same as name of bundle p = strrchr(dir_path, '/'); // Assume name of executable inside bundle is same as name of bundle if (p == NULL) p = dir_path - 1; strlcat(fullpath, p+1, sizeof(fullpath)); p = strrchr(fullpath, '.'); // Strip off bundle extension (".app") if (p) *p = '\0'; sprintf(buf1, "%s:%s", boinc_master_user_name, boinc_master_group_name); // chown boinc_master:boinc_master path/BOINCManager.app/Contents/MacOS/BOINCManager err = DoPrivilegedExec(chownPath, buf1, fullpath, NULL, NULL, NULL, NULL); if (err) return err; #ifdef _DEBUG // chmod u=rwx,g=rwx,o=rx path/BOINCManager.app/Contents/MacOS/BOINCManager // 0775 = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH // Set read, write and execute permission for user & group, read & execute for others err = DoPrivilegedExec(chmodPath, "u=rwx,g=rwx,o=rx", fullpath, NULL, NULL, NULL, NULL); #else // chmod u=rx,g=rx,o=rx path/BOINCManager.app/Contents/MacOS/BOINCManager // 0555 = S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH // Set read and execute permission for user, group & others err = DoPrivilegedExec(chmodPath, "u=rx,g=rx,o=rx", fullpath, NULL, NULL, NULL, NULL); #endif if (err) return err; // Get the full path to BOINC Clients inside this application's bundle strlcpy(fullpath, dir_path, sizeof(fullpath)); strlcat(fullpath, "/Contents/Resources/boinc", sizeof(fullpath)); if (strlen(fullpath) >= (MAXPATHLEN-1)) { ShowSecurityError("SetBOINCAppOwnersGroupsAndPermissions: path to client is too long"); return -1; } sprintf(buf1, "%s:%s", boinc_master_user_name, boinc_master_group_name); // chown boinc_master:boinc_master path/BOINCManager.app/Contents/Resources/boinc err = DoPrivilegedExec(chownPath, buf1, fullpath, NULL, NULL, NULL, NULL); if (err) return err; #ifdef _DEBUG // chmod u=rwsx,g=rwsx,o=rx path/BOINCManager.app/Contents/Resources/boinc // 06775 = S_ISUID | S_ISGID | S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH // Set setuid-on-execution, setgid-on-execution plus read, write and execute permission for user & group, read & execute for others err = DoPrivilegedExec(chmodPath, "u=rwsx,g=rwsx,o=rx", fullpath, NULL, NULL, NULL, NULL); #else // chmod u=rsx,g=rsx,o=rx path/BOINCManager.app/Contents/Resources/boinc // 06555 = S_ISUID | S_ISGID | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH // Set setuid-on-execution, setgid-on-execution plus read and execute permission for user, group & others err = DoPrivilegedExec(chmodPath, "u=rsx,g=rsx,o=rx", fullpath, NULL, NULL, NULL, NULL); #endif if (err) return err; for (int i=0; i<NUMBRANDS; i++) { // Version 6 screensaver has its own embedded switcher application, but older versions don't. // We don't allow unauthorized users to run the switcher application in the BOINC Data directory // because they could use it to run as user & group boinc_project and damage project files. // The screensaver's switcher application runs as user and group "nobody" to avoid this risk. // Does switcher exist in screensaver bundle? sprintf(fullpath, "/Library/Screen Savers/%s.saver/Contents/Resources/gfx_switcher", saverName[i]); err = FSPathMakeRef((StringPtr)fullpath, &ref, &isDirectory); // Does it exist? if ((err == noErr) && (! isDirectory)) { #ifdef _DEBUG sprintf(buf1, "%s:%s", boinc_master_user_name, boinc_master_group_name); // chown boinc_master:boinc_master "/Library/Screen Savers/BOINCSaver.saver/Contents/Resources/gfx_switcher" err = DoPrivilegedExec(chownPath, buf1, fullpath, NULL, NULL, NULL, NULL); if (err) return err; // chmod u=rwx,g=rwx,o=rx "/Library/Screen Savers/BOINCSaver.saver/Contents/Resources/gfx_switcher" // 0775 = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH // Set read, write and execute permission for user & group; read and execute permission for others err = DoPrivilegedExec(chmodPath, "u=rwx,g=rwx,o=rx", fullpath, NULL, NULL, NULL, NULL); if (err) return err; #else sprintf(buf1, "root:%s", boinc_master_group_name); // chown root:boinc_master "/Library/Screen Savers/BOINCSaver.saver/Contents/Resources/gfx_switcher" err = DoPrivilegedExec(chownPath, buf1, fullpath, NULL, NULL, NULL, NULL); if (err) return err; // chmod u=rsx,g=rx,o=rx "/Library/Screen Savers/BOINCSaver.saver/Contents/Resources/gfx_switcher" // 04555 = S_ISUID | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH // Set setuid-on-execution plus read and execute permission for user, group & others err = DoPrivilegedExec(chmodPath, "u=rsx,g=rx,o=rx", fullpath, NULL, NULL, NULL, NULL); if (err) return err; #endif } } return noErr; }
int main(int argc, char *argv[]) { Boolean Success; ProcessSerialNumber ourProcess, installerPSN; short itemHit; long brandID = 0; int i; pid_t installerPID = 0, coreClientPID = 0, waitPermissionsPID = 0; FSRef fileRef; OSStatus err, err_fsref; FILE *f; char s[256]; char *q; #ifdef SANDBOX uid_t saved_euid, saved_uid, b_m_uid; passwd *pw; int finalInstallAction; DialogRef theWin; #else // SANDBOX group *grp; #endif // SANDBOX appName[0] = "/Applications/BOINCManager.app"; appNameEscaped[0] = "/Applications/BOINCManager.app"; brandName[0] = "BOINC"; saverName[0] = "BOINCSaver"; saverNameEscaped[0] = "BOINCSaver"; receiptNameEscaped[0] = "/Library/Receipts/BOINC.pkg"; appName[1] = "/Applications/GridRepublic Desktop.app"; appNameEscaped[1] = "/Applications/GridRepublic\\ Desktop.app"; brandName[1] = "GridRepublic"; saverName[1] = "GridRepublic"; saverNameEscaped[1] = "GridRepublic"; receiptNameEscaped[1] = "/Library/Receipts/GridRepublic.pkg"; appName[2] = "/Applications/Progress Thru Processors Desktop.app"; appNameEscaped[2] = "/Applications/Progress\\ Thru\\ Processors\\ Desktop.app"; brandName[2] = "Progress Thru Processors"; saverName[2] = "Progress Thru Processors"; saverNameEscaped[2] = "Progress\\ Thru\\ Processors"; receiptNameEscaped[2] = "/Library/Receipts/Progress\\ Thru\\ Processors.pkg"; ::GetCurrentProcess (&ourProcess); // getlogin() gives unreliable results under OS 10.6.2, so use environment strncpy(loginName, getenv("USER"), sizeof(loginName)-1); err = Gestalt(gestaltSystemVersion, &OSVersion); if (err != noErr) return err; for (i=0; i<argc; i++) { if (strcmp(argv[i], "-part2") == 0) return DeleteReceipt(); } Initialize(); QuitBOINCManager('BNC!'); // Quit any old instance of BOINC manager sleep(2); // Core Client may still be running if it was started without Manager coreClientPID = FindProcessPID("boinc", 0); if (coreClientPID) kill(coreClientPID, SIGTERM); // boinc catches SIGTERM & exits gracefully err = FindProcess ('APPL', 'xins', &installerPSN); if (err == noErr) err = GetProcessPID(&installerPSN , &installerPID); brandID = GetBrandID(); if ((brandID < 0) || (brandID >= NUMBRANDS)) { // Safety check brandID = 0; } if (OSVersion < 0x1040) { ::SetFrontProcess(&ourProcess); // Remove everything we've installed // "\pSorry, this version of GridRepublic requires system 10.4.0 or higher." s[0] = sprintf(s+1, "Sorry, this version of %s requires system 10.4.0 or higher.", brandName[brandID]); StandardAlert (kAlertStopAlert, (StringPtr)s, NULL, NULL, &itemHit); // "rm -rf /Applications/GridRepublic\\ Desktop.app" sprintf(s, "rm -rf %s", appNameEscaped[brandID]); system (s); // "rm -rf /Library/Screen\\ Savers/GridRepublic.saver" sprintf(s, "rm -rf /Library/Screen\\ Savers/%s.saver", saverNameEscaped[brandID]); system (s); // "rm -rf /Library/Receipts/GridRepublic.pkg" sprintf(s, "rm -rf %s", receiptNameEscaped[brandID]); system (s); // We don't customize BOINC Data directory name for branding system ("rm -rf /Library/Application\\ Support/BOINC\\ Data"); err = kill(installerPID, SIGKILL); ExitToShell(); } sleep (2); // Install all_projects_list.xml file, but only if one doesn't // already exist, since a pre-existing one is probably newer. f = fopen("/Library/Application Support/BOINC Data/all_projects_list.xml", "r"); if (f) { fclose(f); // Already exists } else { system ("cp -fp Contents/Resources/all_projects_list.xml /Library/Application\\ Support/BOINC\\ Data/"); system ("chmod a-x /Library/Application\\ Support/BOINC\\ Data/all_projects_list.xml"); } Success = false; #ifdef SANDBOX CheckUserAndGroupConflicts(); for (i=0; i<5; ++i) { err = CreateBOINCUsersAndGroups(); if (err != noErr) { // print_to_log_file("CreateBOINCUsersAndGroups returned %d (repetition=%d)", err, i); continue; } // err = SetBOINCAppOwnersGroupsAndPermissions("/Applications/GridRepublic Desktop.app"); err = SetBOINCAppOwnersGroupsAndPermissions(appName[brandID]); if (err != noErr) { // print_to_log_file("SetBOINCAppOwnersGroupsAndPermissions returned %d (repetition=%d)", err, i); continue; } err = SetBOINCDataOwnersGroupsAndPermissions(); if (err != noErr) { // print_to_log_file("SetBOINCDataOwnersGroupsAndPermissions returned %d (repetition=%d)", err, i); continue; } err = check_security(appName[brandID], "/Library/Application Support/BOINC Data", true, false); if (err == noErr) break; // print_to_log_file("check_security returned %d (repetition=%d)", err, i); } #else // ! defined(SANDBOX) // The BOINC Manager and Core Client have the set-user-ID-on-execution // flag set, so their ownership is important and must match the // ownership of the BOINC Data directory. // Find an appropriate admin user to set as owner of installed files // First, try the user currently logged in grp = getgrnam("admin"); i = 0; while ((p = grp->gr_mem[i]) != NULL) { // Step through all users in group admin if (strcmp(p, loginName) == 0) { Success = true; // Logged in user is a member of group admin break; } ++i; } // If currently logged in user is not admin, use first non-root admin user if (!Success) { i = 0; while ((p = grp->gr_mem[i]) != NULL) { // Step through all users in group admin if (strcmp(p, "root") != 0) break; ++i; } } // Set owner of branded BOINCManager and contents, including core client // "chown -Rf username /Applications/GridRepublic\\ Desktop.app" sprintf(s, "chown -Rf %s %s", p, appNameEscaped[brandID]); system (s); // Set owner of BOINC Screen Saver // "chown -Rf username /Library/Screen\\ Savers/GridRepublic.saver" sprintf(s, "chown -Rf %s /Library/Screen\\ Savers/%s.saver", p, saverNameEscaped[brandID]); system (s); // We don't customize BOINC Data directory name for branding // "chown -Rf username /Library/Application\\ Support/BOINC\\ Data" sprintf(s, "chown -Rf %s /Library/Application\\ Support/BOINC\\ Data", p); system (s); // "chmod -R a+s /Applications/GridRepublic\\ Desktop.app" sprintf(s, "chmod -R a+s %s", appNameEscaped[brandID]); system (s); #endif // ! defined(SANDBOX) // Remove any branded versions of BOINC other than ours (i.e., old versions) for (i=0; i< NUMBRANDS; i++) { if (i == brandID) continue; // "rm -rf /Applications/GridRepublic\\ Desktop.app" sprintf(s, "rm -rf %s", appNameEscaped[i]); system (s); // "rm -rf /Library/Screen\\ Savers/GridRepublic.saver" sprintf(s, "rm -rf /Library/Screen\\ Savers/%s.saver", saverNameEscaped[i]); system (s); } if (brandID == 0) { // Installing generic BOINC system ("rm -f /Library/Application\\ Support/BOINC\\ Data/Branding"); } // err_fsref = FSPathMakeRef((StringPtr)"/Applications/GridRepublic Desktop.app", &fileRef, NULL); err_fsref = FSPathMakeRef((StringPtr)appName[brandID], &fileRef, NULL); if (err_fsref == noErr) err = LSRegisterFSRef(&fileRef, true); err = UpdateAllVisibleUsers(brandID); if (err != noErr) return err; #ifdef SANDBOX err = CheckLogoutRequirement(&finalInstallAction); if (finalInstallAction == launchWhenDone) { // Wait for BOINC's RPC socket address to become available to user boinc_master, in // case we are upgrading from a version which did not run as user boinc_master. saved_uid = getuid(); saved_euid = geteuid(); pw = getpwnam("boinc_master"); b_m_uid = pw->pw_uid; seteuid(b_m_uid); for (i=0; i<120; i++) { err = TestRPCBind(); if (err == noErr) break; sleep(1); } seteuid(saved_euid); ProcessSerialNumber ourPSN; ProcessInfoRec pInfo; FSRef ourFSRef, theFSRef; char thePath[MAXPATHLEN]; // Get the full path to this PostInstall application's bundle err = GetCurrentProcess (&ourPSN); if (err) return -1000; // Should never happen memset(&pInfo, 0, sizeof(pInfo)); pInfo.processInfoLength = sizeof( ProcessInfoRec ); err = GetProcessInformation(&ourPSN, &pInfo); if (err) return -1001; // Should never happen err = GetProcessBundleLocation(&ourPSN, &ourFSRef); if (err) return -1002; // Should never happen err = FSRefMakePath (&ourFSRef, (UInt8*)thePath, sizeof(thePath)); if (err) return -1003; // Should never happen q = strrchr(thePath, '/'); if (q == NULL) return -1004; // Should never happen *++q = '\0'; strlcat(thePath, "WaitPermissions.app", sizeof(thePath)); err = FSPathMakeRef((StringPtr)thePath, &theFSRef, NULL); // When we first create the boinc_master group and add the current user to the // new group, there is a delay before the new group membership is recognized. // If we launch the BOINC Manager too soon, it will fail with a -1037 permissions // error, so we wait until the current user can access the switcher application. // Apparently, in order to get the changed permissions / group membership, we must // launch a new process belonging to the user. It may also need to be in a new // process group or new session. Neither system() nor popen() works, even after // setting the uid and euid back to the logged in user, but LSOpenFSRef() does. // The WaitPermissions application loops until it can access the switcher // application. err = LSOpenFSRef(&theFSRef, NULL); waitPermissionsStartTime = time(NULL); for (i=0; i<15; i++) { // Show "Please wait..." alert after 15 seconds waitPermissionsPID = FindProcessPID("WaitPermissions", 0); if (waitPermissionsPID == 0) { return 0; } sleep(1); } CreateStandardAlert(kAlertNoteAlert, CFSTR("Finishing install. Please wait ..."), CFSTR("This may take a few more minutes."), NULL, &theWin); HideDialogItem(theWin, kStdOkItemIndex); RemoveDialogItems(theWin, kStdOkItemIndex, 1, false); RunStandardAlert(theWin, &myFilterProc, &itemHit); } #endif // SANDBOX return 0; }
int main(int argc, char *argv[]) { char pkgPath[MAXPATHLEN]; char temp[MAXPATHLEN]; char brand[64], s[256]; char *p; ProcessSerialNumber ourPSN; FSRef ourFSRef; OSStatus err = noErr; Boolean restartNeeded = true; FILE *restartNeededFile; Initialize(); // Get the full path to Installer package inside this application's bundle err = GetCurrentProcess (&ourPSN); if (err == noErr) err = GetProcessBundleLocation(&ourPSN, &ourFSRef); if (err == noErr) err = FSRefMakePath (&ourFSRef, (UInt8*)pkgPath, sizeof(pkgPath)); strlcpy(temp, pkgPath, sizeof(temp)); strlcat(pkgPath, "/Contents/Resources/", sizeof(pkgPath)); // To allow for branding, assume name of installer package inside bundle corresponds to name of this application p = strrchr(temp, '/'); // Point to name of this application (e.g., "BOINC Installer.app") if (p == NULL) p = temp - 1; strlcpy(brand, p+1, sizeof(brand)); strlcat(pkgPath, p+1, sizeof(pkgPath)); p = strrchr(pkgPath, ' '); // Strip off last space character and everything following if (p) *p = '\0'; p = strstr(brand, " Installer.app"); // Strip off trailing " Installer.app" if (p) *p = '\0'; strlcat(pkgPath, ".pkg", sizeof(pkgPath)); // Expand the installer package system("rm -dfR /tmp/BOINC.pkg"); system("rm -dfR /tmp/expanded_BOINC.pkg"); sprintf(temp, "pkgutil --expand \"%s\" /tmp/expanded_BOINC.pkg", pkgPath); err = system(temp); if (err == noErr) { GetPreferredLanguages(); } if (compareOSVersionTo(10, 5) < 0) { LoadPreferredLanguages(); ::SetFrontProcess(&ourPSN); p = strrchr(brand, ' '); // Strip off last space character and everything following if (p) *p = '\0'; ShowMessage((char *)_("Sorry, this version of %s requires system 10.5 or higher."), brand); system("rm -dfR /tmp/BOINC_payload"); return -1; } system("rm -dfR /tmp/BOINC_payload"); // Remove previous installer package receipt so we can run installer again // (affects only older versions of OS X and fixes a bug in those versions) // "rm -rf /Library/Receipts/GridRepublic.pkg" sprintf(s, "rm -rf \"/Library/Receipts/%s.pkg\"", brand); system (s); restartNeeded = IsRestartNeeded(); // Write a temp file to tell our PostInstall.app whether restart is needed restartNeededFile = fopen("/tmp/BOINC_restart_flag", "w"); if (restartNeededFile) { fputs(restartNeeded ? "1\n" : "0\n", restartNeededFile); fclose(restartNeededFile); } if (restartNeeded) { if (err == noErr) { // Change onConclusion="none" to onConclusion="RequireRestart" err = system("sed -i \"\" s/\"onConclusion=\\\"none\\\"\"/\"onConclusion=\\\"RequireRestart\\\"\"/g /tmp/expanded_BOINC.pkg/Distribution"); } if (err == noErr) { // Flatten the installer package sprintf(temp, "pkgutil --flatten /tmp/expanded_BOINC.pkg /tmp/%s.pkg", brand); err = system(temp); system("rm -fR /tmp/expanded_BOINC.pkg"); } if (err == noErr) { sprintf(temp, "open \"/tmp/%s.pkg\" &", brand); system(temp); return 0; } } sprintf(temp, "open \"%s\" &", pkgPath); system(temp); return err; }