+++ /dev/null
-/*
- * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
- *
- * The contents of this file constitute Original Code as defined in and are
- * subject to the Apple Public Source License Version 1.2 (the 'License').
- * You may not use this file except in compliance with the License. Please obtain
- * a copy of the License at http://www.apple.com/publicsource and read it before
- * using this file.
- *
- * This Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
- * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
- * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
- * specific language governing rights and limitations under the License.
- */
-
-
-//
-// trampolineClient - Authorization trampoline client-side implementation
-//
-#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/debugging.h>
-
-//
-// Where is the trampoline itself?
-//
-#if !defined(TRAMPOLINE)
-# define TRAMPOLINE "/System/Library/CoreServices/AuthorizationTrampoline" /* fallback */
-#endif
-
-
-//
-// A few names for clarity's sake
-//
-enum {
- READ = 0, // read end of standard UNIX pipe
- WRITE = 1 // write end of standard UNIX pipe
-};
-
-
-//
-// Local (static) functions
-//
-static const char **argVector(const char *trampoline,
- const char *tool, const char *commFd,
- char *const *arguments);
-
-
-//
-// The public client API function.
-//
-OSStatus AuthorizationExecuteWithPrivileges(AuthorizationRef authorization,
- const char *pathToTool,
- unsigned long flags,
- char *const *arguments,
- FILE **communicationsPipe)
-{
- // flags are currently reserved
- if (flags != 0)
- return errAuthorizationInvalidFlags;
-
- // externalize the authorization
- AuthorizationExternalForm extForm;
- if (OSStatus err = AuthorizationMakeExternalForm(authorization, &extForm))
- return err;
-
- // create the mailbox file
- FILE *mbox = tmpfile();
- if (!mbox)
- return errAuthorizationInternal;
- if (fwrite(&extForm, sizeof(extForm), 1, mbox) != 1) {
- fclose(mbox);
- return errAuthorizationInternal;
- }
- fflush(mbox);
-
- // make text representation of the temp-file descriptor
- char mboxFdText[20];
- snprintf(mboxFdText, sizeof(mboxFdText), "auth %d", fileno(mbox));
-
- // make a notifier pipe
- int notify[2];
- if (pipe(notify)) {
- fclose(mbox);
- return errAuthorizationToolExecuteFailure;
- }
-
- // make the communications pipe if requested
- int comm[2];
- if (communicationsPipe && socketpair(AF_UNIX, SOCK_STREAM, 0, comm)) {
- close(notify[READ]); close(notify[WRITE]);
- fclose(mbox);
- return errAuthorizationToolExecuteFailure;
- }
-
- // do the standard forking tango...
- int delay = 1;
- for (int n = 5;; n--, delay *= 2) {
- switch (fork()) {
- case -1: // error
- if (errno == EAGAIN) {
- // potentially recoverable resource shortage
- 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: // parent
- // close foreign side of pipes
- close(notify[WRITE]);
- if (communicationsPipe)
- close(comm[WRITE]);
-
- // close mailbox file (child has it open now)
- fclose(mbox);
-
- // get status notification from child
- OSStatus status;
- secdebug("authexec", "parent waiting for status");
- switch (IFDEBUG(ssize_t rc =) read(notify[READ], &status, sizeof(status))) {
- default: // weird result of read: post error
- secdebug("authexec", "unexpected read return value %ld", long(rc));
- status = errAuthorizationToolEnvironmentError;
- // fall through
- case sizeof(status): // read succeeded: child reported an error
- secdebug("authexec", "parent received status=%ld", status);
- close(notify[READ]);
- if (communicationsPipe) { close(comm[READ]); close(comm[WRITE]); }
- return status;
- case 0: // end of file: exec succeeded
- close(notify[READ]);
- if (communicationsPipe)
- *communicationsPipe = fdopen(comm[READ], "r+");
- secdebug("authexec", "parent resumes (no error)");
- return noErr;
- }
-
- case 0: // child
- // close foreign side of pipes
- close(notify[READ]);
- if (communicationsPipe)
- close(comm[READ]);
-
- // fd 1 (stdout) holds the notify write end
- dup2(notify[WRITE], 1);
- close(notify[WRITE]);
-
- // fd 0 (stdin) holds either the comm-link write-end or /dev/null
- if (communicationsPipe) {
- dup2(comm[WRITE], 0);
- close(comm[WRITE]);
- } else {
- close(0);
- open("/dev/null", O_RDWR);
- }
-
- // where is the trampoline?
-#if defined(NDEBUG)
- const char *trampoline = TRAMPOLINE;
-#else //!NDEBUG
- const char *trampoline = getenv("AUTHORIZATIONTRAMPOLINE");
- if (!trampoline)
- trampoline = TRAMPOLINE;
-#endif //NDEBUG
-
- // okay, execute the trampoline
- secdebug("authexec", "child exec(%s:%s)",
- trampoline, pathToTool);
- if (const char **argv = argVector(trampoline, pathToTool, mboxFdText, arguments))
- execv(trampoline, (char *const*)argv);
- secdebug("authexec", "trampoline exec failed (errno=%d)", errno);
-
- // execute failed - tell the parent
- {
- OSStatus error = errAuthorizationToolExecuteFailure;
- write(1, &error, sizeof(error));
- _exit(1);
- }
- }
- }
-}
-
-
-//
-// Build an argv vector
-//
-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;
-}