1/* 2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved. 3 * 4 * The contents of this file constitute Original Code as defined in and are 5 * subject to the Apple Public Source License Version 1.2 (the 'License'). 6 * You may not use this file except in compliance with the License. Please obtain 7 * a copy of the License at http://www.apple.com/publicsource and read it before 8 * using this file. 9 * 10 * This Original Code and all software distributed under the License are 11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS 12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT 13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the 15 * specific language governing rights and limitations under the License. 16 */ 17 18 19// 20// AuthorizationTrampoline - simple suid-root execution trampoline 21// for the authorization API. 22// 23#include <errno.h> 24#include <stdlib.h> 25#include <unistd.h> 26#include <fcntl.h> 27#include <syslog.h> 28#include <Security/Authorization.h> 29#include <Security/AuthorizationTags.h> 30#include <security_utilities/endian.h> 31#include <security_utilities/debugging.h> 32#include <security_utilities/logging.h> 33 34 35#define EXECUTERIGHT kAuthorizationRightExecute 36 37 38static void fail(OSStatus cause) __attribute__ ((noreturn)); 39 40 41// 42// Main program entry point. 43// 44// Arguments: 45// argv[0] = my name 46// argv[1] = path to user tool 47// argv[2] = "auth n", n=file descriptor of mailbox temp file 48// argv[3..n] = arguments to pass on 49// 50// File descriptors (set by fork/exec code in client): 51// 0 -> communications pipe (perhaps /dev/null) 52// 1 -> notify pipe write end 53// 2 and above -> unchanged from original client 54// 55int main(int argc, const char *argv[]) 56{ 57 // initial setup 58 Syslog::open("authexec", LOG_AUTH); 59 60 // validate basic integrity 61 if (!argv[0] || !argv[1] || !argv[2]) { 62 Syslog::alert("invalid argument vector"); 63 exit(1); 64 } 65 66 // pick up arguments 67 const char *pathToTool = argv[1]; 68 const char *mboxFdText = argv[2]; 69 const char **restOfArguments = argv + 3; 70 secdebug("authtramp", "trampoline(%s,%s)", pathToTool, mboxFdText); 71 72 // read the external form 73 AuthorizationExternalForm extForm; 74 int fd; 75 if (sscanf(mboxFdText, "auth %d", &fd) != 1) 76 return errAuthorizationInternal; 77 if (lseek(fd, 0, SEEK_SET) || 78 read(fd, &extForm, sizeof(extForm)) != sizeof(extForm)) { 79 close(fd); 80 return errAuthorizationInternal; 81 } 82 83 // internalize the authorization 84 AuthorizationRef auth; 85 if (OSStatus error = AuthorizationCreateFromExternalForm(&extForm, &auth)) 86 fail(error); 87 secdebug("authtramp", "authorization recovered"); 88 89 // are we allowed to do this? 90 AuthorizationItem right = { EXECUTERIGHT, 0, NULL, 0 }; 91 AuthorizationRights inRights = { 1, &right }; 92 AuthorizationRights *outRights; 93 if (OSStatus error = AuthorizationCopyRights(auth, &inRights, NULL /*env*/, 94 kAuthorizationFlagExtendRights | kAuthorizationFlagInteractionAllowed, &outRights)) 95 fail(error); 96 if (outRights->count != 1 || strcmp(outRights->items[0].name, EXECUTERIGHT)) 97 fail(errAuthorizationDenied); 98 99 // ----- AT THIS POINT WE COMMIT TO PERMITTING THE EXECUTION ----- 100 101 // let go of our authorization - the client tool will re-internalize it 102 AuthorizationFree(auth, kAuthorizationFlagDefaults); 103 104 // put the external authorization form into the environment 105 setenv("__AUTHORIZATION", mboxFdText, true); 106 setenv("_BASH_IMPLICIT_DASH_PEE", "-p", true); 107 108 // shuffle file descriptors 109 int notify = dup(1); // save notify port 110 fcntl(notify, F_SETFD, 1); // close notify port on (successful) exec 111 dup2(0, 1); // make stdin, stdout point to the comms pipe 112 113 // prepare the argv for the tool (prepend the "myself" element) 114 // note how this overwrites a known-existing argv element (that we copied earlier) 115 *(--restOfArguments) = pathToTool; 116 117 secdebug("authtramp", "trampoline executes %s", pathToTool); 118 Syslog::notice("executing %s", pathToTool); 119 execv(pathToTool, (char *const *)restOfArguments); 120 secdebug("authexec", "exec(%s) failed (errno=%d)", pathToTool, errno); 121 122 // report failure 123 OSStatus error = h2n(OSStatus(errAuthorizationToolExecuteFailure)); 124 write(notify, &error, sizeof(error)); 125 exit(1); 126} 127 128 129void fail(OSStatus cause) 130{ 131 OSStatus tmp = h2n(cause); 132 write(1, &tmp, sizeof(tmp)); // ignore error - can't do anything if error 133 secdebug("authtramp", "trampoline aborting with status %ld", cause); 134 exit(1); 135} 136