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 // trampolineClient - Authorization trampoline client-side implementation
22 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <Security/Authorization.h>
29 #include <Security/debugging.h>
32 // Where is the trampoline itself?
34 #if !defined(TRAMPOLINE)
35 # define TRAMPOLINE "/System/Library/CoreServices/AuthorizationTrampoline" /* fallback */
40 // A few names for clarity's sake
43 READ
= 0, // read end of standard UNIX pipe
44 WRITE
= 1 // write end of standard UNIX pipe
49 // Local (static) functions
51 static const char **argVector(const char *trampoline
,
52 const char *tool
, const char *commFd
,
53 char *const *arguments
);
57 // The public client API function.
59 OSStatus
AuthorizationExecuteWithPrivileges(AuthorizationRef authorization
,
60 const char *pathToTool
,
62 char *const *arguments
,
63 FILE **communicationsPipe
)
65 // flags are currently reserved
67 return errAuthorizationInvalidFlags
;
69 // externalize the authorization
70 AuthorizationExternalForm extForm
;
71 if (OSStatus err
= AuthorizationMakeExternalForm(authorization
, &extForm
))
74 // create the mailbox file
75 FILE *mbox
= tmpfile();
77 return errAuthorizationInternal
;
78 if (fwrite(&extForm
, sizeof(extForm
), 1, mbox
) != 1) {
80 return errAuthorizationInternal
;
84 // make text representation of the temp-file descriptor
86 snprintf(mboxFdText
, sizeof(mboxFdText
), "auth %d", fileno(mbox
));
88 // make a notifier pipe
92 return errAuthorizationToolExecuteFailure
;
95 // make the communications pipe if requested
97 if (communicationsPipe
&& socketpair(AF_UNIX
, SOCK_STREAM
, 0, comm
)) {
98 close(notify
[READ
]); close(notify
[WRITE
]);
100 return errAuthorizationToolExecuteFailure
;
103 // do the standard forking tango...
105 for (int n
= 5;; n
--, delay
*= 2) {
106 switch (pid_t pid
= fork()) {
108 if (errno
== EAGAIN
) {
109 // potentially recoverable resource shortage
111 debug("authexec", "resource shortage (EAGAIN), delaying %d seconds", delay
);
116 debug("authexec", "fork failed (errno=%d)", errno
);
117 close(notify
[READ
]); close(notify
[WRITE
]);
118 return errAuthorizationToolExecuteFailure
;
121 // close foreign side of pipes
122 close(notify
[WRITE
]);
123 if (communicationsPipe
)
126 // close mailbox file (child has it open now)
129 // get status notification from child
131 debug("authexec", "parent waiting for status");
132 switch (ssize_t rc
= read(notify
[READ
], &status
, sizeof(status
))) {
133 default: // weird result of read: post error
134 debug("authexec", "unexpected read return value %ld", long(rc
));
135 status
= errAuthorizationToolEnvironmentError
;
137 case sizeof(status
): // read succeeded: child reported an error
138 debug("authexec", "parent received status=%ld", status
);
140 if (communicationsPipe
) { close(comm
[READ
]); close(comm
[WRITE
]); }
142 case 0: // end of file: exec succeeded
144 if (communicationsPipe
)
145 *communicationsPipe
= fdopen(comm
[READ
], "r+");
146 debug("authexec", "parent resumes (no error)");
151 // close foreign side of pipes
153 if (communicationsPipe
)
156 // fd 1 (stdout) holds the notify write end
157 dup2(notify
[WRITE
], 1);
158 close(notify
[WRITE
]);
160 // fd 0 (stdin) holds either the comm-link write-end or /dev/null
161 if (communicationsPipe
) {
162 dup2(comm
[WRITE
], 0);
166 open("/dev/null", O_RDWR
);
169 // where is the trampoline?
171 const char *trampoline
= TRAMPOLINE
;
173 const char *trampoline
= getenv("AUTHORIZATIONTRAMPOLINE");
175 trampoline
= TRAMPOLINE
;
178 // okay, execute the trampoline
179 debug("authexec", "child exec(%s:%s)",
180 trampoline
, pathToTool
);
181 if (const char **argv
= argVector(trampoline
, pathToTool
, mboxFdText
, arguments
))
182 execv(trampoline
, (char *const[])argv
);
183 debug("authexec", "trampoline exec failed (errno=%d)", errno
);
185 // execute failed - tell the parent
187 OSStatus error
= errAuthorizationToolExecuteFailure
;
188 write(1, &error
, sizeof(error
));
197 // Build an argv vector
199 static const char **argVector(const char *trampoline
, const char *pathToTool
,
200 const char *mboxFdText
, char *const *arguments
)
204 for (char *const *p
= arguments
; *p
; p
++)
207 if (const char **args
= (const char **)malloc(sizeof(const char *) * (length
+ 4))) {
208 args
[0] = trampoline
;
209 args
[1] = pathToTool
;
210 args
[2] = mboxFdText
;
212 for (int n
= 0; arguments
[n
]; n
++)
213 args
[n
+ 3] = arguments
[n
];
214 args
[length
+ 3] = NULL
;