]> git.saurik.com Git - apple/security.git/blob - libsecurity_authorization/lib/trampolineClient.cpp
Security-55163.44.tar.gz
[apple/security.git] / libsecurity_authorization / lib / trampolineClient.cpp
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 //
26 // trampolineClient - Authorization trampoline client-side implementation
27 //
28 #include <asl.h>
29 #include <sys/types.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <stdlib.h>
34 #include <sys/socket.h>
35 #include <Security/Authorization.h>
36 #include <security_utilities/endian.h>
37 #include <security_utilities/debugging.h>
38
39 //
40 // Where is the trampoline itself?
41 //
42 #if !defined(TRAMPOLINE)
43 # define TRAMPOLINE "/usr/libexec/security_authtrampoline" /* fallback */
44 #endif
45
46
47 //
48 // A few names for clarity's sake
49 //
50 enum {
51 READ = 0, // read end of standard UNIX pipe
52 WRITE = 1 // write end of standard UNIX pipe
53 };
54
55
56 //
57 // Local (static) functions
58 //
59 static const char **argVector(const char *trampoline,
60 const char *tool, const char *commFd,
61 char *const *arguments);
62
63
64 //
65 // The public client API function.
66 //
67 OSStatus AuthorizationExecuteWithPrivileges(AuthorizationRef authorization,
68 const char *pathToTool,
69 AuthorizationFlags flags,
70 char *const *arguments,
71 FILE **communicationsPipe)
72 {
73 // report the caller to the authorities
74 aslmsg m = asl_new(ASL_TYPE_MSG);
75 asl_set(m, "com.apple.message.domain", "com.apple.libsecurity_authorization.AuthorizationExecuteWithPrivileges");
76 asl_set(m, "com.apple.message.signature", getprogname());
77 asl_log(NULL, m, ASL_LEVEL_NOTICE, "AuthorizationExecuteWithPrivileges!");
78 asl_free(m);
79
80 // flags are currently reserved
81 if (flags != 0)
82 return errAuthorizationInvalidFlags;
83
84 // externalize the authorization
85 AuthorizationExternalForm extForm;
86 if (OSStatus err = AuthorizationMakeExternalForm(authorization, &extForm))
87 return err;
88
89 // create the mailbox file
90 FILE *mbox = tmpfile();
91 if (!mbox)
92 return errAuthorizationInternal;
93 if (fwrite(&extForm, sizeof(extForm), 1, mbox) != 1) {
94 fclose(mbox);
95 return errAuthorizationInternal;
96 }
97 fflush(mbox);
98
99 // make text representation of the temp-file descriptor
100 char mboxFdText[20];
101 snprintf(mboxFdText, sizeof(mboxFdText), "auth %d", fileno(mbox));
102
103 // make a notifier pipe
104 int notify[2];
105 if (pipe(notify)) {
106 fclose(mbox);
107 return errAuthorizationToolExecuteFailure;
108 }
109
110 // make the communications pipe if requested
111 int comm[2];
112 if (communicationsPipe && socketpair(AF_UNIX, SOCK_STREAM, 0, comm)) {
113 close(notify[READ]); close(notify[WRITE]);
114 fclose(mbox);
115 return errAuthorizationToolExecuteFailure;
116 }
117
118 // do the standard forking tango...
119 int delay = 1;
120 for (int n = 5;; n--, delay *= 2) {
121 switch (fork()) {
122 case -1: // error
123 if (errno == EAGAIN) {
124 // potentially recoverable resource shortage
125 if (n > 0) {
126 secdebug("authexec", "resource shortage (EAGAIN), delaying %d seconds", delay);
127 sleep(delay);
128 continue;
129 }
130 }
131 secdebug("authexec", "fork failed (errno=%d)", errno);
132 close(notify[READ]); close(notify[WRITE]);
133 return errAuthorizationToolExecuteFailure;
134
135 default: { // parent
136 // close foreign side of pipes
137 close(notify[WRITE]);
138 if (communicationsPipe)
139 close(comm[WRITE]);
140
141 // close mailbox file (child has it open now)
142 fclose(mbox);
143
144 // get status notification from child
145 OSStatus status;
146 secdebug("authexec", "parent waiting for status");
147 ssize_t rc = read(notify[READ], &status, sizeof(status));
148 status = n2h(status);
149 switch (rc) {
150 default: // weird result of read: post error
151 secdebug("authexec", "unexpected read return value %ld", long(rc));
152 status = errAuthorizationToolEnvironmentError;
153 // fall through
154 case sizeof(status): // read succeeded: child reported an error
155 secdebug("authexec", "parent received status=%d", (int)status);
156 close(notify[READ]);
157 if (communicationsPipe) { close(comm[READ]); close(comm[WRITE]); }
158 return status;
159 case 0: // end of file: exec succeeded
160 close(notify[READ]);
161 if (communicationsPipe)
162 *communicationsPipe = fdopen(comm[READ], "r+");
163 secdebug("authexec", "parent resumes (no error)");
164 return noErr;
165 }
166 }
167
168 case 0: // child
169 // close foreign side of pipes
170 close(notify[READ]);
171 if (communicationsPipe)
172 close(comm[READ]);
173
174 // fd 1 (stdout) holds the notify write end
175 dup2(notify[WRITE], 1);
176 close(notify[WRITE]);
177
178 // fd 0 (stdin) holds either the comm-link write-end or /dev/null
179 if (communicationsPipe) {
180 dup2(comm[WRITE], 0);
181 close(comm[WRITE]);
182 } else {
183 close(0);
184 open("/dev/null", O_RDWR);
185 }
186
187 // where is the trampoline?
188 #if defined(NDEBUG)
189 const char *trampoline = TRAMPOLINE;
190 #else //!NDEBUG
191 const char *trampoline = getenv("AUTHORIZATIONTRAMPOLINE");
192 if (!trampoline)
193 trampoline = TRAMPOLINE;
194 #endif //NDEBUG
195
196 // okay, execute the trampoline
197 secdebug("authexec", "child exec(%s:%s)",
198 trampoline, pathToTool);
199 if (const char **argv = argVector(trampoline, pathToTool, mboxFdText, arguments))
200 execv(trampoline, (char *const*)argv);
201 secdebug("authexec", "trampoline exec failed (errno=%d)", errno);
202
203 // execute failed - tell the parent
204 {
205 OSStatus error = errAuthorizationToolExecuteFailure;
206 error = h2n(error);
207 write(1, &error, sizeof(error));
208 _exit(1);
209 }
210 }
211 }
212 }
213
214
215 //
216 // Build an argv vector
217 //
218 static const char **argVector(const char *trampoline, const char *pathToTool,
219 const char *mboxFdText, char *const *arguments)
220 {
221 int length = 0;
222 if (arguments) {
223 for (char *const *p = arguments; *p; p++)
224 length++;
225 }
226 if (const char **args = (const char **)malloc(sizeof(const char *) * (length + 4))) {
227 args[0] = trampoline;
228 args[1] = pathToTool;
229 args[2] = mboxFdText;
230 if (arguments)
231 for (int n = 0; arguments[n]; n++)
232 args[n + 3] = arguments[n];
233 args[length + 3] = NULL;
234 return args;
235 }
236 return NULL;
237 }