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