|
|
OSStatus AuthorizationExecuteWithPrivilegesStdErrAndPid (
AuthorizationRef authorization,
const char *pathToTool,
AuthorizationFlags options,
char * const *arguments,
FILE **communicationsPipe,
FILE **errPipe,
pid_t* processid
)
{
char stderrpath[] = "/tmp/AuthorizationExecuteWithPrivilegesStdErrXXXXXXX.err" ;
const char* commandtemplate = "echo $$; \"$@\" 2>%s" ;
if (communicationsPipe == errPipe) {
commandtemplate = "echo $$; \"$@\" 2>1";
} else if (errPipe == 0) {
commandtemplate = "echo $$; \"$@\"";
}
char command[1024];
char ** args;
OSStatus result;
int argcount = 0;
int i;
int stderrfd = 0;
FILE* commPipe = 0;
/* Create temporary file for stderr */
if (errPipe) {
stderrfd = mkstemps (stderrpath, strlen(".err"));
/* create a pipe on that path */
close(stderrfd); unlink(stderrpath);
if (mkfifo(stderrpath,S_IRWXU | S_IRWXG) != 0) {
fprintf(stderr,"Error mkfifo:%d\n",errno);
return errAuthorizationInternal;
}
if (stderrfd < 0)
return errAuthorizationInternal;
}
/* Create command to be executed */
for (argcount = 0; arguments[argcount] != 0; ++argcount) {}
args = (char**)malloc (sizeof(char*)*(argcount + 5));
args[0] = "-c";
snprintf (command, sizeof (command), commandtemplate, stderrpath);
args[1] = command;
args[2] = "";
args[3] = (char*)pathToTool;
for (i = 0; i < argcount; ++i) {
args[i+4] = arguments[i];
}
args[argcount+4] = 0;
/* for debugging: log the executed command */
/* printf ("Exec:\n%s", "/bin/sh"); for (i = 0; args[i] != 0; ++i) { printf (" \"%s\"", args[i]); } printf ("\n"); */
/* Execute command */
result = AuthorizationExecuteWithPrivileges(
authorization, "/bin/sh", options, args, &commPipe );
if (result != noErr) {
unlink (stderrpath);
return result;
}
/* Read the first line of stdout => it's the pid */
{
int stdoutfd = fileno (commPipe);
char pidnum[1024];
pid_t pid = 0;
int i = 0;
char ch = 0;
while ((read(stdoutfd, &ch, sizeof(ch)) == 1) && (ch != '\n') && (i < sizeof(pidnum))) {
pidnum[i++] = ch;
}
pidnum[i] = 0;
if (ch != '\n') {
// we shouldn't get there
unlink (stderrpath);
return errAuthorizationInternal;
}
sscanf(pidnum, "%d", &pid);
if (processid) {
*processid = pid;
}
}
if (errPipe) {
stderrfd = open(stderrpath, O_RDONLY, 0);
*errPipe = fdopen(stderrfd, "r");
/* Now it's safe to unlink the stderr file, as the opened handle will be still valid */
unlink (stderrpath);
} else {
unlink(stderrpath);
}
if (communicationsPipe) {
*communicationsPipe = commPipe;
} else {
fclose (commPipe);
}
return noErr;
}
|