trampolineClient.cpp [plain text]
#include <asl.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <Security/Authorization.h>
#include <Security/AuthorizationPriv.h>
#include <Security/SecBase.h>
#include <security_utilities/endian.h>
#include <security_utilities/debugging.h>
#if !defined(TRAMPOLINE)
# define TRAMPOLINE "/usr/libexec/security_authtrampoline"
#endif
enum {
READ = 0, WRITE = 1 };
static const char **argVector(const char *trampoline,
const char *tool, const char *commFd,
char *const *arguments);
OSStatus AuthorizationExecuteWithPrivileges(AuthorizationRef authorization,
const char *pathToTool,
AuthorizationFlags flags,
char *const *arguments,
FILE **communicationsPipe)
{
AuthorizationExternalForm extForm;
if (OSStatus err = AuthorizationMakeExternalForm(authorization, &extForm))
return err;
return AuthorizationExecuteWithPrivilegesExternalForm(&extForm, pathToTool, flags, arguments, communicationsPipe);
}
OSStatus AuthorizationExecuteWithPrivilegesExternalForm(const AuthorizationExternalForm * extForm,
const char *pathToTool,
AuthorizationFlags flags,
char *const *arguments,
FILE **communicationsPipe)
{
if (extForm == NULL)
return errAuthorizationInvalidPointer;
aslmsg m = asl_new(ASL_TYPE_MSG);
asl_set(m, "com.apple.message.domain", "com.apple.libsecurity_authorization.AuthorizationExecuteWithPrivileges");
asl_set(m, "com.apple.message.signature", getprogname());
asl_log(NULL, m, ASL_LEVEL_NOTICE, "AuthorizationExecuteWithPrivileges!");
asl_free(m);
if (flags != 0)
return errAuthorizationInvalidFlags;
FILE *mbox = tmpfile();
if (!mbox)
return errAuthorizationInternal;
if (fwrite(extForm, sizeof(*extForm), 1, mbox) != 1) {
fclose(mbox);
return errAuthorizationInternal;
}
fflush(mbox);
char mboxFdText[20];
snprintf(mboxFdText, sizeof(mboxFdText), "auth %d", fileno(mbox));
#if defined(NDEBUG)
const char *trampoline = TRAMPOLINE;
#else //!NDEBUG
const char *trampoline = getenv("AUTHORIZATIONTRAMPOLINE");
if (!trampoline)
trampoline = TRAMPOLINE;
#endif //NDEBUG
const char **argv = argVector(trampoline, pathToTool, mboxFdText, arguments);
int notify[2];
if (pipe(notify)) {
fclose(mbox);
return errAuthorizationToolExecuteFailure;
}
int comm[2];
if (communicationsPipe && socketpair(AF_UNIX, SOCK_STREAM, 0, comm)) {
close(notify[READ]); close(notify[WRITE]);
fclose(mbox);
return errAuthorizationToolExecuteFailure;
}
OSStatus status = errSecSuccess;
int delay = 1;
for (int n = 5;; n--, delay *= 2) {
switch (fork()) {
case -1: if (errno == EAGAIN) {
if (n > 0) {
secdebug("authexec", "resource shortage (EAGAIN), delaying %d seconds", delay);
sleep(delay);
continue;
}
}
secdebug("authexec", "fork failed (errno=%d)", errno);
close(notify[READ]); close(notify[WRITE]);
return errAuthorizationToolExecuteFailure;
default: { close(notify[WRITE]);
if (communicationsPipe)
close(comm[WRITE]);
fclose(mbox);
secdebug("authexec", "parent waiting for status");
ssize_t rc = read(notify[READ], &status, sizeof(status));
status = n2h(status);
switch (rc) {
default: secdebug("authexec", "unexpected read return value %ld", long(rc));
status = errAuthorizationToolEnvironmentError;
case sizeof(status): secdebug("authexec", "parent received status=%d", (int)status);
close(notify[READ]);
if (communicationsPipe) { close(comm[READ]); close(comm[WRITE]); }
goto exit_point;
case 0: close(notify[READ]);
if (communicationsPipe)
*communicationsPipe = fdopen(comm[READ], "r+");
secdebug("authexec", "parent resumes (no error)");
status = errSecSuccess;
goto exit_point;
}
}
break;
case 0: close(notify[READ]);
if (communicationsPipe)
close(comm[READ]);
dup2(notify[WRITE], 1);
close(notify[WRITE]);
if (communicationsPipe) {
dup2(comm[WRITE], 0);
close(comm[WRITE]);
} else {
close(0);
open("/dev/null", O_RDWR);
}
if (argv)
execv(trampoline, (char *const*)argv);
{
OSStatus error = errAuthorizationToolExecuteFailure;
error = h2n(error);
write(1, &error, sizeof(error));
_exit(1);
}
}
}
exit_point:
free(argv);
return status;
}
static const char **argVector(const char *trampoline, const char *pathToTool,
const char *mboxFdText, char *const *arguments)
{
int length = 0;
if (arguments) {
for (char *const *p = arguments; *p; p++)
length++;
}
if (const char **args = (const char **)malloc(sizeof(const char *) * (length + 4))) {
args[0] = trampoline;
args[1] = pathToTool;
args[2] = mboxFdText;
if (arguments)
for (int n = 0; arguments[n]; n++)
args[n + 3] = arguments[n];
args[length + 3] = NULL;
return args;
}
return NULL;
}