bool ElectronBundleMover::AuthorizedInstall()

in shell/browser/ui/cocoa/electron_bundle_mover.mm [261:362]


bool ElectronBundleMover::AuthorizedInstall(NSString* srcPath,
                                            NSString* dstPath,
                                            bool* canceled) {
  if (canceled)
    *canceled = false;

  // Make sure that the destination path is an app bundle. We're essentially
  // running 'sudo rm -rf' so we really don't want to screw this up.
  if (![[dstPath pathExtension] isEqualToString:@"app"])
    return false;

  // Do some more checks
  if ([[dstPath stringByTrimmingCharactersInSet:[NSCharacterSet
                                                    whitespaceCharacterSet]]
          length] == 0)
    return false;
  if ([[srcPath stringByTrimmingCharactersInSet:[NSCharacterSet
                                                    whitespaceCharacterSet]]
          length] == 0)
    return false;

  int pid, status;
  AuthorizationRef myAuthorizationRef;

  // Get the authorization
  OSStatus err =
      AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment,
                          kAuthorizationFlagDefaults, &myAuthorizationRef);
  if (err != errAuthorizationSuccess)
    return false;

  AuthorizationItem myItems = {kAuthorizationRightExecute, 0, NULL, 0};
  AuthorizationRights myRights = {1, &myItems};
  AuthorizationFlags myFlags = (AuthorizationFlags)(
      kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights |
      kAuthorizationFlagPreAuthorize);

  err = AuthorizationCopyRights(myAuthorizationRef, &myRights, NULL, myFlags,
                                NULL);
  if (err != errAuthorizationSuccess) {
    if (err == errAuthorizationCanceled && canceled)
      *canceled = true;
    goto fail;
  }

  static OSStatus (*security_AuthorizationExecuteWithPrivileges)(
      AuthorizationRef authorization, const char* pathToTool,
      AuthorizationFlags options, char* const* arguments,
      FILE** communicationsPipe) = NULL;
  if (!security_AuthorizationExecuteWithPrivileges) {
    // On 10.7, AuthorizationExecuteWithPrivileges is deprecated. We want to
    // still use it since there's no good alternative (without requiring code
    // signing). We'll look up the function through dyld and fail if it is no
    // longer accessible. If Apple removes the function entirely this will fail
    // gracefully. If they keep the function and throw some sort of exception,
    // this won't fail gracefully, but that's a risk we'll have to take for now.
    security_AuthorizationExecuteWithPrivileges = (OSStatus(*)(
        AuthorizationRef, const char*, AuthorizationFlags, char* const*,
        FILE**))dlsym(RTLD_DEFAULT, "AuthorizationExecuteWithPrivileges");
  }
  if (!security_AuthorizationExecuteWithPrivileges)
    goto fail;

  // Delete the destination
  {
    char rf[] = "-rf";
    char* args[] = {rf, (char*)[dstPath fileSystemRepresentation], NULL};
    err = security_AuthorizationExecuteWithPrivileges(
        myAuthorizationRef, "/bin/rm", kAuthorizationFlagDefaults, args, NULL);
    if (err != errAuthorizationSuccess)
      goto fail;

    // Wait until it's done
    pid = wait(&status);
    if (pid == -1 || !WIFEXITED(status))
      goto fail;  // We don't care about exit status as the destination most
                  // likely does not exist
  }

  // Copy
  {
    char pR[] = "-pR";
    char* args[] = {pR, (char*)[srcPath fileSystemRepresentation],
                    (char*)[dstPath fileSystemRepresentation], NULL};
    err = security_AuthorizationExecuteWithPrivileges(
        myAuthorizationRef, "/bin/cp", kAuthorizationFlagDefaults, args, NULL);
    if (err != errAuthorizationSuccess)
      goto fail;

    // Wait until it's done
    pid = wait(&status);
    if (pid == -1 || !WIFEXITED(status) || WEXITSTATUS(status))
      goto fail;
  }

  AuthorizationFree(myAuthorizationRef, kAuthorizationFlagDefaults);
  return true;

fail:
  AuthorizationFree(myAuthorizationRef, kAuthorizationFlagDefaults);
  return false;
}