2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
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
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.
20 // AuthorizationTrampoline - simple suid-root execution trampoline
21 // for the authorization API.
27 #include <Security/Authorization.h>
28 #include <Security/debugging.h>
29 #include <Security/logging.h>
32 #define EXECUTERIGHT "system.privilege.admin"
35 static void fail(OSStatus cause
) __attribute__ ((noreturn
));
39 // Main program entry point.
43 // argv[1] = path to user tool
44 // argv[2] = "auth n", n=file descriptor of mailbox temp file
45 // argv[3..n] = arguments to pass on
47 // File descriptors (set by fork/exec code in client):
48 // 0 -> communications pipe (perhaps /dev/null)
49 // 1 -> notify pipe write end
50 // 2 and above -> unchanged from original client
52 int main(int argc
, const char *argv
[])
55 Syslog::open("authexec", LOG_AUTH
);
57 // validate basic integrity
58 if (!argv
[0] || !argv
[1] || !argv
[2]) {
59 Syslog::alert("invalid argument vector");
64 const char *pathToTool
= argv
[1];
65 const char *mboxFdText
= argv
[2];
66 const char **restOfArguments
= argv
+ 3;
67 debug("authtramp", "trampoline(%s,%s)", pathToTool
, mboxFdText
);
69 // read the external form
70 AuthorizationExternalForm extForm
;
72 if (sscanf(mboxFdText
, "auth %d", &fd
) != 1)
73 return errAuthorizationInternal
;
74 if (lseek(fd
, 0, SEEK_SET
) ||
75 read(fd
, &extForm
, sizeof(extForm
)) != sizeof(extForm
)) {
77 return errAuthorizationInternal
;
80 // internalize the authorization
81 AuthorizationRef auth
;
82 if (OSStatus error
= AuthorizationCreateFromExternalForm(&extForm
, &auth
))
84 debug("authtramp", "authorization recovered");
86 // are we allowed to do this?
87 AuthorizationItem right
= { EXECUTERIGHT
, 0, NULL
, 0 };
88 AuthorizationRights inRights
= { 1, &right
};
89 AuthorizationRights
*outRights
;
90 if (OSStatus error
= AuthorizationCopyRights(auth
, &inRights
, NULL
/*env*/,
91 kAuthorizationFlagExtendRights
| kAuthorizationFlagInteractionAllowed
, &outRights
))
93 if (outRights
->count
!= 1 || strcmp(outRights
->items
[0].name
, EXECUTERIGHT
))
94 fail(errAuthorizationDenied
);
96 // ----- AT THIS POINT WE COMMIT TO PERMITTING THE EXECUTION -----
98 // let go of our authorization - the client tool will re-internalize it
99 AuthorizationFree(auth
, kAuthorizationFlagDefaults
);
101 // put the external authorization form into the environment
102 setenv("__AUTHORIZATION", mboxFdText
, true);
104 // shuffle file descriptors
105 int notify
= dup(1); // save notify port
106 fcntl(notify
, F_SETFD
, 1); // close notify port on (successful) exec
107 dup2(0, 1); // make stdin, stdout point to the comms pipe
109 // prepare the argv for the tool (prepend the "myself" element)
110 // note how this overwrites a known-existing argv element (that we copied earlier)
111 *(--restOfArguments
) = pathToTool
;
113 debug("authtramp", "trampoline executes %s", pathToTool
);
114 Syslog::notice("executing %s", pathToTool
);
115 execv(pathToTool
, (char *const *)restOfArguments
);
116 debug("authexec", "exec(%s) failed (errno=%d)", pathToTool
, errno
);
119 OSStatus error
= errAuthorizationToolExecuteFailure
;
120 write(notify
, &error
, sizeof(error
));
125 void fail(OSStatus cause
)
127 write(1, &cause
, sizeof(cause
)); // ignore error - can't do anything if error
128 debug("authtramp", "trampoline aborting with status %ld", cause
);