2 * Copyright (c) 2000-2004,2011-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 // trampolineClient - Authorization trampoline client-side implementation
29 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <Security/Authorization.h>
36 #include <Security/AuthorizationPriv.h>
37 #include <Security/SecBase.h>
38 #include <security_utilities/endian.h>
39 #include <security_utilities/debugging.h>
42 // Where is the trampoline itself?
44 #if !defined(TRAMPOLINE)
45 # define TRAMPOLINE "/usr/libexec/security_authtrampoline" /* fallback */
50 // A few names for clarity's sake
53 READ
= 0, // read end of standard UNIX pipe
54 WRITE
= 1 // write end of standard UNIX pipe
59 // Local (static) functions
61 static const char **argVector(const char *trampoline
,
62 const char *tool
, const char *commFd
,
63 char *const *arguments
);
66 OSStatus
AuthorizationExecuteWithPrivileges(AuthorizationRef authorization
,
67 const char *pathToTool
,
68 AuthorizationFlags flags
,
69 char *const *arguments
,
70 FILE **communicationsPipe
)
72 // externalize the authorization
73 AuthorizationExternalForm extForm
;
74 if (OSStatus err
= AuthorizationMakeExternalForm(authorization
, &extForm
))
77 return AuthorizationExecuteWithPrivilegesExternalForm(&extForm
, pathToTool
, flags
, arguments
, communicationsPipe
);
81 // The public client API function.
83 OSStatus
AuthorizationExecuteWithPrivilegesExternalForm(const AuthorizationExternalForm
* extForm
,
84 const char *pathToTool
,
85 AuthorizationFlags flags
,
86 char *const *arguments
,
87 FILE **communicationsPipe
)
90 return errAuthorizationInvalidPointer
;
92 // report the caller to the authorities
93 aslmsg m
= asl_new(ASL_TYPE_MSG
);
94 asl_set(m
, "com.apple.message.domain", "com.apple.libsecurity_authorization.AuthorizationExecuteWithPrivileges");
95 asl_set(m
, "com.apple.message.signature", getprogname());
96 asl_log(NULL
, m
, ASL_LEVEL_NOTICE
, "AuthorizationExecuteWithPrivileges!");
99 // flags are currently reserved
101 return errAuthorizationInvalidFlags
;
103 // compute the argument vector here because we can't allocate memory once we fork.
105 // where is the trampoline?
107 const char *trampoline
= TRAMPOLINE
;
109 const char *trampoline
= getenv("AUTHORIZATIONTRAMPOLINE");
111 trampoline
= TRAMPOLINE
;
114 // make a data exchange pipe
116 if (pipe(dataPipe
)) {
117 secinfo("authexec", "data pipe failure");
118 return errAuthorizationToolExecuteFailure
;
121 // make text representation of the pipe handle
123 snprintf(pipeFdText
, sizeof(pipeFdText
), "auth %d", dataPipe
[READ
]);
124 const char **argv
= argVector(trampoline
, pathToTool
, pipeFdText
, arguments
);
126 // make a notifier pipe
129 close(dataPipe
[READ
]); close(dataPipe
[WRITE
]);
133 secinfo("authexec", "notify pipe failure");
134 return errAuthorizationToolExecuteFailure
;
137 // make the communications pipe if requested
139 if (communicationsPipe
&& socketpair(AF_UNIX
, SOCK_STREAM
, 0, comm
)) {
140 close(notify
[READ
]); close(notify
[WRITE
]);
141 close(dataPipe
[READ
]); close(dataPipe
[WRITE
]);
145 secinfo("authexec", "comm pipe failure");
146 return errAuthorizationToolExecuteFailure
;
149 OSStatus status
= errSecSuccess
;
151 // do the standard forking tango...
153 for (int n
= 5;; n
--, delay
*= 2) {
156 if (errno
== EAGAIN
) {
157 // potentially recoverable resource shortage
159 secinfo("authexec", "resource shortage (EAGAIN), delaying %d seconds", delay
);
164 secinfo("authexec", "fork failed (errno=%d)", errno
);
165 close(notify
[READ
]); close(notify
[WRITE
]);
166 status
= errAuthorizationToolExecuteFailure
;
170 // close foreign side of pipes
171 close(notify
[WRITE
]);
172 if (communicationsPipe
)
175 close(dataPipe
[READ
]);
176 if (write(dataPipe
[WRITE
], extForm
, sizeof(*extForm
)) != sizeof(*extForm
)) {
177 secinfo("authexec", "fwrite data failed (errno=%d)", errno
);
178 status
= errAuthorizationInternal
;
180 close(dataPipe
[WRITE
]);
181 if (communicationsPipe
) {
187 close(dataPipe
[WRITE
]);
188 // get status notification from child
189 secinfo("authexec", "parent waiting for status");
190 ssize_t rc
= read(notify
[READ
], &status
, sizeof(status
));
191 status
= n2h(status
);
193 default: // weird result of read: post error
194 secinfo("authexec", "unexpected read return value %ld", long(rc
));
195 status
= errAuthorizationToolEnvironmentError
;
197 case sizeof(status
): // read succeeded: child reported an error
198 secinfo("authexec", "parent received status=%d", (int)status
);
200 close(dataPipe
[WRITE
]);
201 if (communicationsPipe
) {
206 case 0: // end of file: exec succeeded
208 close(dataPipe
[WRITE
]);
209 if (communicationsPipe
)
210 *communicationsPipe
= fdopen(comm
[READ
], "r+");
211 secinfo("authexec", "parent resumes (no error)");
212 status
= errSecSuccess
;
218 // close foreign side of pipes
220 if (communicationsPipe
)
223 // close write end of the data PIPE
224 close(dataPipe
[WRITE
]);
226 // fd 1 (stdout) holds the notify write end
227 dup2(notify
[WRITE
], 1);
228 close(notify
[WRITE
]);
230 // fd 0 (stdin) holds either the comm-link write-end or /dev/null
231 if (communicationsPipe
) {
232 dup2(comm
[WRITE
], 0);
236 open("/dev/null", O_RDWR
);
239 // okay, execute the trampoline
241 execv(trampoline
, (char *const*)argv
);
243 // execute failed - tell the parent
245 // in case of failure, close read end of the data pipe as well
246 close(dataPipe
[WRITE
]);
247 close(dataPipe
[READ
]);
248 OSStatus error
= errAuthorizationToolExecuteFailure
;
250 write(1, &error
, sizeof(error
));
263 // Build an argv vector
265 static const char **argVector(const char *trampoline
, const char *pathToTool
,
266 const char *mboxFdText
, char *const *arguments
)
270 for (char *const *p
= arguments
; *p
; p
++)
273 if (const char **args
= (const char **)malloc(sizeof(const char *) * (length
+ 4))) {
274 args
[0] = trampoline
;
275 args
[1] = pathToTool
;
276 args
[2] = mboxFdText
;
278 for (int n
= 0; arguments
[n
]; n
++)
279 args
[n
+ 3] = arguments
[n
];
280 args
[length
+ 3] = NULL
;