2 * Copyright (c) 1999-2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_APACHE_LICENSE_HEADER_START@
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 * @APPLE_APACHE_LICENSE_HEADER_END@
23 #include "launch_priv.h"
24 #include "bootstrap.h"
25 #include "bootstrap_priv.h"
27 #include "vproc_priv.h"
29 #include <mach/mach.h>
30 #include <mach/vm_map.h>
31 #include <sys/types.h>
32 #include <sys/syslog.h>
36 #include "protocol_vproc.h"
39 bootstrap_create_server(mach_port_t bp
, cmd_t server_cmd
, uid_t server_uid
, boolean_t on_demand
, mach_port_t
*server_port
)
43 kr
= vproc_mig_create_server(bp
, server_cmd
, server_uid
, on_demand
, server_port
);
45 if (kr
== VPROC_ERR_TRY_PER_USER
) {
48 if (vproc_mig_lookup_per_user_context(bp
, 0, &puc
) == 0) {
49 kr
= vproc_mig_create_server(puc
, server_cmd
, server_uid
, on_demand
, server_port
);
50 mach_port_deallocate(mach_task_self(), puc
);
58 bootstrap_subset(mach_port_t bp
, mach_port_t requestor_port
, mach_port_t
*subset_port
)
60 return vproc_mig_subset(bp
, requestor_port
, subset_port
);
64 bootstrap_unprivileged(mach_port_t bp
, mach_port_t
*unpriv_port
)
68 *unpriv_port
= MACH_PORT_NULL
;
70 kr
= mach_port_mod_refs(mach_task_self(), bp
, MACH_PORT_RIGHT_SEND
, 1);
72 if (kr
== KERN_SUCCESS
) {
80 bootstrap_parent(mach_port_t bp
, mach_port_t
*parent_port
)
82 return vproc_mig_parent(bp
, parent_port
);
86 bootstrap_register(mach_port_t bp
, name_t service_name
, mach_port_t sp
)
88 return bootstrap_register2(bp
, service_name
, sp
, 0);
92 bootstrap_register2(mach_port_t bp
, name_t service_name
, mach_port_t sp
, uint64_t flags
)
94 kern_return_t kr
= vproc_mig_register2(bp
, service_name
, sp
, flags
);
96 if (kr
== VPROC_ERR_TRY_PER_USER
) {
99 if (vproc_mig_lookup_per_user_context(bp
, 0, &puc
) == 0) {
100 kr
= vproc_mig_register2(puc
, service_name
, sp
, flags
);
101 mach_port_deallocate(mach_task_self(), puc
);
109 bootstrap_create_service(mach_port_t bp
, name_t service_name
, mach_port_t
*sp
)
113 if ((kr
= bootstrap_check_in(bp
, service_name
, sp
))) {
117 if ((kr
= mach_port_mod_refs(mach_task_self(), *sp
, MACH_PORT_RIGHT_RECEIVE
, -1))) {
121 return bootstrap_look_up(bp
, service_name
, sp
);
125 bootstrap_check_in(mach_port_t bp
, const name_t service_name
, mach_port_t
*sp
)
127 return vproc_mig_check_in2(bp
, (char *)service_name
, sp
, 0);
131 bootstrap_check_in2(mach_port_t bp
, const name_t service_name
, mach_port_t
*sp
, uint64_t flags
)
133 return vproc_mig_check_in2(bp
, (char *)service_name
, sp
, flags
);
137 bootstrap_look_up_per_user(mach_port_t bp
, const name_t service_name
, uid_t target_user
, mach_port_t
*sp
)
139 audit_token_t au_tok
;
143 /* See rdar://problem/4890134. */
145 if ((kr
= vproc_mig_lookup_per_user_context(bp
, target_user
, &puc
)) != 0) {
149 if( !service_name
) {
152 kr
= vproc_mig_look_up2(puc
, (char *)service_name
, sp
, &au_tok
, 0, 0);
153 mach_port_deallocate(mach_task_self(), puc
);
160 bootstrap_lookup_children(mach_port_t bp
, mach_port_array_t
*children
, name_array_t
*names
, bootstrap_property_array_t
*properties
, mach_msg_type_number_t
*n_children
)
162 mach_msg_type_number_t junk
= 0;
163 return vproc_mig_lookup_children(bp
, children
, &junk
, names
, n_children
, properties
, &junk
);
167 bootstrap_look_up(mach_port_t bp
, const name_t service_name
, mach_port_t
*sp
)
169 return bootstrap_look_up2(bp
, service_name
, sp
, 0, 0);
173 bootstrap_look_up2(mach_port_t bp
, const name_t service_name
, mach_port_t
*sp
, pid_t target_pid
, uint64_t flags
)
175 static pthread_mutex_t bslu2_lock
= PTHREAD_MUTEX_INITIALIZER
;
176 static mach_port_t prev_bp
;
177 static mach_port_t prev_sp
;
178 static name_t prev_name
;
179 audit_token_t au_tok
;
180 bool per_pid_lookup
= flags
& BOOTSTRAP_PER_PID_SERVICE
;
181 bool privileged_server_lookup
= flags
& BOOTSTRAP_PRIVILEGED_SERVER
;
182 kern_return_t kr
= 0;
185 pthread_mutex_lock(&bslu2_lock
);
187 if (per_pid_lookup
|| privileged_server_lookup
) {
192 if ((bp
== prev_bp
) && (strncmp(prev_name
, service_name
, sizeof(name_t
)) == 0)
193 && (mach_port_mod_refs(mach_task_self(), prev_sp
, MACH_PORT_RIGHT_SEND
, 1) == 0)) {
197 mach_port_deallocate(mach_task_self(), prev_sp
);
203 if ((kr
= vproc_mig_look_up2(bp
, (char *)service_name
, sp
, &au_tok
, target_pid
, flags
)) != VPROC_ERR_TRY_PER_USER
) {
207 if ((kr
= vproc_mig_lookup_per_user_context(bp
, 0, &puc
)) != 0) {
211 kr
= vproc_mig_look_up2(puc
, (char *)service_name
, sp
, &au_tok
, target_pid
, flags
);
212 mach_port_deallocate(mach_task_self(), puc
);
215 if (!(per_pid_lookup
|| privileged_server_lookup
) && kr
== 0 && prev_sp
== 0 && mach_port_mod_refs(mach_task_self(), *sp
, MACH_PORT_RIGHT_SEND
, 1) == 0) {
216 /* We're going to hold on to a send right as a MRU cache */
219 strlcpy(prev_name
, service_name
, sizeof(name_t
));
222 if ((kr
== 0) && privileged_server_lookup
) {
226 * The audit token magic is dependent on the per-user launchd
227 * forwarding MIG requests to the root launchd when it cannot
228 * find the answer locally.
231 /* This API should be in Libsystem, but is not */
232 //audit_token_to_au32(au_tok, NULL, &server_euid, NULL, NULL, NULL, NULL, NULL, NULL);
234 server_euid
= au_tok
.val
[1];
237 mach_port_deallocate(mach_task_self(), *sp
);
238 kr
= BOOTSTRAP_NOT_PRIVILEGED
;
241 /* If performance becomes a problem, we should restructure this. */
242 pthread_mutex_unlock(&bslu2_lock
);
248 bootstrap_status(mach_port_t bp
, name_t service_name
, bootstrap_status_t
*service_active
)
253 if ((kr
= bootstrap_look_up(bp
, service_name
, &p
))) {
257 mach_port_deallocate(mach_task_self(), p
);
258 *service_active
= BOOTSTRAP_STATUS_ACTIVE
;
260 if (bootstrap_check_in(bp
, service_name
, &p
) == BOOTSTRAP_SUCCESS
) {
261 mach_port_mod_refs(mach_task_self(), p
, MACH_PORT_RIGHT_RECEIVE
, -1);
262 *service_active
= BOOTSTRAP_STATUS_ON_DEMAND
;
265 return BOOTSTRAP_SUCCESS
;
269 bootstrap_info(mach_port_t bp
,
270 name_array_t
*service_names
, mach_msg_type_number_t
*service_namesCnt
,
271 name_array_t
*service_jobs
, mach_msg_type_number_t
*service_jobsCnt
,
272 bootstrap_status_array_t
*service_active
, mach_msg_type_number_t
*service_activeCnt
,
275 return vproc_mig_info(bp
, service_names
, service_namesCnt
, service_jobs
, service_jobsCnt
, service_active
, service_activeCnt
, flags
);
279 bootstrap_strerror(kern_return_t r
)
282 case BOOTSTRAP_SUCCESS
:
284 case BOOTSTRAP_NOT_PRIVILEGED
:
285 return "Permission denied";
286 case BOOTSTRAP_NAME_IN_USE
:
287 case BOOTSTRAP_SERVICE_ACTIVE
:
288 return "Service name already exists";
289 case BOOTSTRAP_UNKNOWN_SERVICE
:
290 return "Unknown service name";
291 case BOOTSTRAP_BAD_COUNT
:
292 return "Too many lookups were requested in one request";
293 case BOOTSTRAP_NO_MEMORY
:
294 return "Out of memory";
296 return mach_error_string(r
);