]> git.saurik.com Git - apple/security.git/blob - SecurityServer/Authorization/trampolineClient.cpp
Security-54.tar.gz
[apple/security.git] / SecurityServer / Authorization / trampolineClient.cpp
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 // trampolineClient - Authorization trampoline client-side implementation
21 //
22 #include <sys/types.h>
23 #include <unistd.h>
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <stdlib.h>
27 #include <sys/socket.h>
28 #include <Security/Authorization.h>
29 #include <Security/debugging.h>
30
31 //
32 // Where is the trampoline itself?
33 //
34 #if !defined(TRAMPOLINE)
35 # define TRAMPOLINE "/System/Library/CoreServices/AuthorizationTrampoline" /* fallback */
36 #endif
37
38
39 //
40 // A few names for clarity's sake
41 //
42 enum {
43 READ = 0, // read end of standard UNIX pipe
44 WRITE = 1 // write end of standard UNIX pipe
45 };
46
47
48 //
49 // Local (static) functions
50 //
51 static const char **argVector(const char *trampoline,
52 const char *tool, const char *commFd,
53 char *const *arguments);
54
55
56 //
57 // The public client API function.
58 //
59 OSStatus AuthorizationExecuteWithPrivileges(AuthorizationRef authorization,
60 const char *pathToTool,
61 unsigned long flags,
62 char *const *arguments,
63 FILE **communicationsPipe)
64 {
65 // flags are currently reserved
66 if (flags != 0)
67 return errAuthorizationInvalidFlags;
68
69 // externalize the authorization
70 AuthorizationExternalForm extForm;
71 if (OSStatus err = AuthorizationMakeExternalForm(authorization, &extForm))
72 return err;
73
74 // create the mailbox file
75 FILE *mbox = tmpfile();
76 if (!mbox)
77 return errAuthorizationInternal;
78 if (fwrite(&extForm, sizeof(extForm), 1, mbox) != 1) {
79 fclose(mbox);
80 return errAuthorizationInternal;
81 }
82 fflush(mbox);
83
84 // make text representation of the temp-file descriptor
85 char mboxFdText[20];
86 snprintf(mboxFdText, sizeof(mboxFdText), "auth %d", fileno(mbox));
87
88 // make a notifier pipe
89 int notify[2];
90 if (pipe(notify)) {
91 fclose(mbox);
92 return errAuthorizationToolExecuteFailure;
93 }
94
95 // make the communications pipe if requested
96 int comm[2];
97 if (communicationsPipe && socketpair(AF_UNIX, SOCK_STREAM, 0, comm)) {
98 close(notify[READ]); close(notify[WRITE]);
99 fclose(mbox);
100 return errAuthorizationToolExecuteFailure;
101 }
102
103 // do the standard forking tango...
104 int delay = 1;
105 for (int n = 5;; n--, delay *= 2) {
106 switch (pid_t pid = fork()) {
107 case -1: // error
108 if (errno == EAGAIN) {
109 // potentially recoverable resource shortage
110 if (n > 0) {
111 debug("authexec", "resource shortage (EAGAIN), delaying %d seconds", delay);
112 sleep(delay);
113 continue;
114 }
115 }
116 debug("authexec", "fork failed (errno=%d)", errno);
117 close(notify[READ]); close(notify[WRITE]);
118 return errAuthorizationToolExecuteFailure;
119
120 default: // parent
121 // close foreign side of pipes
122 close(notify[WRITE]);
123 if (communicationsPipe)
124 close(comm[WRITE]);
125
126 // close mailbox file (child has it open now)
127 fclose(mbox);
128
129 // get status notification from child
130 OSStatus status;
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;
136 // fall through
137 case sizeof(status): // read succeeded: child reported an error
138 debug("authexec", "parent received status=%ld", status);
139 close(notify[READ]);
140 if (communicationsPipe) { close(comm[READ]); close(comm[WRITE]); }
141 return status;
142 case 0: // end of file: exec succeeded
143 close(notify[READ]);
144 if (communicationsPipe)
145 *communicationsPipe = fdopen(comm[READ], "r+");
146 debug("authexec", "parent resumes (no error)");
147 return noErr;
148 }
149
150 case 0: // child
151 // close foreign side of pipes
152 close(notify[READ]);
153 if (communicationsPipe)
154 close(comm[READ]);
155
156 // fd 1 (stdout) holds the notify write end
157 dup2(notify[WRITE], 1);
158 close(notify[WRITE]);
159
160 // fd 0 (stdin) holds either the comm-link write-end or /dev/null
161 if (communicationsPipe) {
162 dup2(comm[WRITE], 0);
163 close(comm[WRITE]);
164 } else {
165 close(0);
166 open("/dev/null", O_RDWR);
167 }
168
169 // where is the trampoline?
170 #if defined(NDEBUG)
171 const char *trampoline = TRAMPOLINE;
172 #else //!NDEBUG
173 const char *trampoline = getenv("AUTHORIZATIONTRAMPOLINE");
174 if (!trampoline)
175 trampoline = TRAMPOLINE;
176 #endif //NDEBUG
177
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);
184
185 // execute failed - tell the parent
186 {
187 OSStatus error = errAuthorizationToolExecuteFailure;
188 write(1, &error, sizeof(error));
189 _exit(1);
190 }
191 }
192 }
193 }
194
195
196 //
197 // Build an argv vector
198 //
199 static const char **argVector(const char *trampoline, const char *pathToTool,
200 const char *mboxFdText, char *const *arguments)
201 {
202 int length = 0;
203 if (arguments) {
204 for (char *const *p = arguments; *p; p++)
205 length++;
206 }
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;
211 if (arguments)
212 for (int n = 0; arguments[n]; n++)
213 args[n + 3] = arguments[n];
214 args[length + 3] = NULL;
215 return args;
216 }
217 return NULL;
218 }