Skip to content

Instantly share code, notes, and snippets.

@autoxr
Created July 16, 2009 03:29
Show Gist options
  • Save autoxr/148142 to your computer and use it in GitHub Desktop.
Save autoxr/148142 to your computer and use it in GitHub Desktop.
+ (BOOL)_copyPathWithForcedAuthentication:(NSString *)src toPath:(NSString *)dst error:(NSError **)error
{
NSString *tmp = [self _temporaryCopyNameForPath:dst];
const char* srcPath = [src fileSystemRepresentation];
const char* tmpPath = [tmp fileSystemRepresentation];
const char* dstPath = [dst fileSystemRepresentation];
struct stat dstSB;
stat(dstPath, &dstSB);
AuthorizationRef auth = NULL;
OSStatus authStat = errAuthorizationDenied;
while (authStat == errAuthorizationDenied) {
authStat = AuthorizationCreate(NULL,
kAuthorizationEmptyEnvironment,
kAuthorizationFlagDefaults,
&auth);
}
BOOL res = NO;
if (authStat == errAuthorizationSuccess) {
res = YES;
char uidgid[42];
snprintf(uidgid, sizeof(uidgid), "%d:%d",
dstSB.st_uid, dstSB.st_gid);
const char* executables[] = {
"/bin/rm",
"/bin/mv",
"/bin/mv",
"/bin/rm",
NULL, // pause here and do some housekeeping before
// continuing
"/usr/sbin/chown",
NULL // stop here for real
};
// 4 is the maximum number of arguments to any command,
// including the NULL that signals the end of an argument
// list.
const char* const argumentLists[][4] = {
{ "-rf", tmpPath, NULL }, // make room for the temporary file... this is kinda unsafe; should probably do something better.
{ "-f", dstPath, tmpPath, NULL }, // mv
{ "-f", srcPath, dstPath, NULL }, // mv
{ "-rf", tmpPath, NULL }, // rm
{ NULL }, // pause
{ "-R", uidgid, dstPath, NULL }, // chown
{ NULL } // stop
};
// Process the commands up until the first NULL
int commandIndex = 0;
for (; executables[commandIndex] != NULL; ++commandIndex) {
if (res)
res = AuthorizationExecuteWithPrivilegesAndWait(auth, executables[commandIndex], kAuthorizationFlagDefaults, argumentLists[commandIndex]);
}
// If the currently-running application is trusted, the new
// version should be trusted as well. Remove it from the
// quarantine to avoid a delay at launch, and to avoid
// presenting the user with a confusing trust dialog.
//
// This needs to be done after the application is moved to its
// new home with "mv" in case it's moved across filesystems: if
// that happens, "mv" actually performs a copy and may result
// in the application being quarantined. It also needs to be
// done before "chown" changes ownership, because the ownership
// change will almost certainly make it impossible to change
// attributes to release the files from the quarantine.
if (res) {
[self releaseFromQuarantine:dst];
}
// Now move past the NULL we found and continue executing
// commands from the list.
++commandIndex;
for (; executables[commandIndex] != NULL; ++commandIndex) {
if (res)
res = AuthorizationExecuteWithPrivilegesAndWait(auth, executables[commandIndex], kAuthorizationFlagDefaults, argumentLists[commandIndex]);
}
AuthorizationFree(auth, 0);
if (!res)
{
// Something went wrong somewhere along the way, but we're not sure exactly where.
NSString *errorMessage = [NSString stringWithFormat:@"Authenticated file copy from %@ to %@ failed.", src, dst];
if (error != NULL)
*error = [NSError errorWithDomain:SUSparkleErrorDomain code:SUAuthenticationFailure userInfo:[NSDictionary dictionaryWithObject:errorMessage forKey:NSLocalizedDescriptionKey]];
}
}
else
{
if (error != NULL)
*error = [NSError errorWithDomain:SUSparkleErrorDomain code:SUAuthenticationFailure userInfo:[NSDictionary dictionaryWithObject:@"Couldn't get permission to authenticate." forKey:NSLocalizedDescriptionKey]];
}
return res;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment