]>
Commit | Line | Data |
---|---|---|
5b0a4722 A |
1 | /* |
2 | * Copyright (c) 1999-2005 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_APACHE_LICENSE_HEADER_START@ | |
5 | * | |
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 | |
9 | * | |
10 | * http://www.apache.org/licenses/LICENSE-2.0 | |
11 | * | |
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. | |
17 | * | |
18 | * @APPLE_APACHE_LICENSE_HEADER_END@ | |
19 | */ | |
20 | ||
21 | #include "config.h" | |
ddbbfbc1 A |
22 | #include "launch.h" |
23 | #include "launch_priv.h" | |
ef398931 A |
24 | #include "bootstrap.h" |
25 | #include "bootstrap_priv.h" | |
ef398931 A |
26 | #include "vproc.h" |
27 | #include "vproc_priv.h" | |
5b0a4722 A |
28 | |
29 | #include <mach/mach.h> | |
30 | #include <mach/vm_map.h> | |
31 | #include <sys/types.h> | |
32 | #include <sys/syslog.h> | |
33 | #include <sys/stat.h> | |
34 | #include <pthread.h> | |
dcace88f | 35 | #include <stdlib.h> |
5b0a4722 | 36 | |
eabd1701 | 37 | #include "job.h" |
5b0a4722 | 38 | |
dcace88f A |
39 | void |
40 | bootstrap_init(void) | |
41 | { | |
42 | kern_return_t kr = task_get_special_port(task_self_trap(), TASK_BOOTSTRAP_PORT, &bootstrap_port); | |
43 | if (kr != KERN_SUCCESS) { | |
44 | abort(); | |
45 | } | |
46 | } | |
47 | ||
5b0a4722 A |
48 | kern_return_t |
49 | bootstrap_create_server(mach_port_t bp, cmd_t server_cmd, uid_t server_uid, boolean_t on_demand, mach_port_t *server_port) | |
50 | { | |
ddbbfbc1 A |
51 | kern_return_t kr; |
52 | ||
53 | kr = vproc_mig_create_server(bp, server_cmd, server_uid, on_demand, server_port); | |
54 | ||
55 | if (kr == VPROC_ERR_TRY_PER_USER) { | |
56 | mach_port_t puc; | |
57 | ||
58 | if (vproc_mig_lookup_per_user_context(bp, 0, &puc) == 0) { | |
59 | kr = vproc_mig_create_server(puc, server_cmd, server_uid, on_demand, server_port); | |
60 | mach_port_deallocate(mach_task_self(), puc); | |
61 | } | |
62 | } | |
63 | ||
64 | return kr; | |
5b0a4722 A |
65 | } |
66 | ||
67 | kern_return_t | |
68 | bootstrap_subset(mach_port_t bp, mach_port_t requestor_port, mach_port_t *subset_port) | |
69 | { | |
70 | return vproc_mig_subset(bp, requestor_port, subset_port); | |
71 | } | |
72 | ||
73 | kern_return_t | |
74 | bootstrap_unprivileged(mach_port_t bp, mach_port_t *unpriv_port) | |
75 | { | |
76 | kern_return_t kr; | |
77 | ||
78 | *unpriv_port = MACH_PORT_NULL; | |
79 | ||
80 | kr = mach_port_mod_refs(mach_task_self(), bp, MACH_PORT_RIGHT_SEND, 1); | |
81 | ||
82 | if (kr == KERN_SUCCESS) { | |
83 | *unpriv_port = bp; | |
84 | } | |
85 | ||
86 | return kr; | |
87 | } | |
88 | ||
89 | kern_return_t | |
90 | bootstrap_parent(mach_port_t bp, mach_port_t *parent_port) | |
91 | { | |
92 | return vproc_mig_parent(bp, parent_port); | |
93 | } | |
94 | ||
5b0a4722 A |
95 | kern_return_t |
96 | bootstrap_register(mach_port_t bp, name_t service_name, mach_port_t sp) | |
97 | { | |
98 | return bootstrap_register2(bp, service_name, sp, 0); | |
99 | } | |
100 | ||
101 | kern_return_t | |
102 | bootstrap_register2(mach_port_t bp, name_t service_name, mach_port_t sp, uint64_t flags) | |
103 | { | |
104 | kern_return_t kr = vproc_mig_register2(bp, service_name, sp, flags); | |
105 | ||
106 | if (kr == VPROC_ERR_TRY_PER_USER) { | |
107 | mach_port_t puc; | |
108 | ||
109 | if (vproc_mig_lookup_per_user_context(bp, 0, &puc) == 0) { | |
110 | kr = vproc_mig_register2(puc, service_name, sp, flags); | |
111 | mach_port_deallocate(mach_task_self(), puc); | |
112 | } | |
113 | } | |
114 | ||
115 | return kr; | |
116 | } | |
117 | ||
118 | kern_return_t | |
119 | bootstrap_create_service(mach_port_t bp, name_t service_name, mach_port_t *sp) | |
120 | { | |
ddbbfbc1 A |
121 | kern_return_t kr; |
122 | ||
123 | if ((kr = bootstrap_check_in(bp, service_name, sp))) { | |
124 | return kr; | |
125 | } | |
126 | ||
127 | if ((kr = mach_port_mod_refs(mach_task_self(), *sp, MACH_PORT_RIGHT_RECEIVE, -1))) { | |
128 | return kr; | |
129 | } | |
130 | ||
131 | return bootstrap_look_up(bp, service_name, sp); | |
5b0a4722 A |
132 | } |
133 | ||
134 | kern_return_t | |
ddbbfbc1 | 135 | bootstrap_check_in(mach_port_t bp, const name_t service_name, mach_port_t *sp) |
5b0a4722 | 136 | { |
dcace88f | 137 | uuid_t junk; |
95379394 | 138 | (void)bzero(junk, sizeof(junk)); |
dcace88f | 139 | return vproc_mig_check_in2(bp, (char *)service_name, sp, junk, 0); |
5b0a4722 A |
140 | } |
141 | ||
142 | kern_return_t | |
ddbbfbc1 | 143 | bootstrap_check_in2(mach_port_t bp, const name_t service_name, mach_port_t *sp, uint64_t flags) |
5b0a4722 | 144 | { |
dcace88f | 145 | uuid_t junk; |
95379394 | 146 | (void)bzero(junk, sizeof(junk)); |
dcace88f | 147 | return vproc_mig_check_in2(bp, (char *)service_name, sp, junk, flags); |
ddbbfbc1 A |
148 | } |
149 | ||
150 | kern_return_t | |
151 | bootstrap_look_up_per_user(mach_port_t bp, const name_t service_name, uid_t target_user, mach_port_t *sp) | |
152 | { | |
153 | audit_token_t au_tok; | |
5b0a4722 A |
154 | kern_return_t kr; |
155 | mach_port_t puc; | |
156 | ||
ddbbfbc1 | 157 | /* See rdar://problem/4890134. */ |
5b0a4722 A |
158 | |
159 | if ((kr = vproc_mig_lookup_per_user_context(bp, target_user, &puc)) != 0) { | |
160 | return kr; | |
161 | } | |
162 | ||
dcace88f | 163 | if (!service_name) { |
ddbbfbc1 A |
164 | *sp = puc; |
165 | } else { | |
dcace88f A |
166 | uuid_t junk; |
167 | kr = vproc_mig_look_up2(puc, (char *)service_name, sp, &au_tok, 0, junk, 0); | |
ddbbfbc1 A |
168 | mach_port_deallocate(mach_task_self(), puc); |
169 | } | |
5b0a4722 A |
170 | |
171 | return kr; | |
172 | } | |
173 | ||
ddbbfbc1 A |
174 | kern_return_t |
175 | 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) | |
176 | { | |
177 | mach_msg_type_number_t junk = 0; | |
178 | return vproc_mig_lookup_children(bp, children, &junk, names, n_children, properties, &junk); | |
179 | } | |
5b0a4722 A |
180 | |
181 | kern_return_t | |
ddbbfbc1 | 182 | bootstrap_look_up(mach_port_t bp, const name_t service_name, mach_port_t *sp) |
5b0a4722 A |
183 | { |
184 | return bootstrap_look_up2(bp, service_name, sp, 0, 0); | |
185 | } | |
186 | ||
187 | kern_return_t | |
ddbbfbc1 | 188 | bootstrap_look_up2(mach_port_t bp, const name_t service_name, mach_port_t *sp, pid_t target_pid, uint64_t flags) |
5b0a4722 | 189 | { |
dcace88f A |
190 | uuid_t instance_id; |
191 | return bootstrap_look_up3(bp, service_name, sp, target_pid, instance_id, flags); | |
192 | } | |
193 | ||
194 | kern_return_t | |
195 | bootstrap_look_up3(mach_port_t bp, const name_t service_name, mach_port_t *sp, pid_t target_pid, const uuid_t instance_id, uint64_t flags) | |
196 | { | |
ddbbfbc1 | 197 | audit_token_t au_tok; |
ddbbfbc1 A |
198 | bool privileged_server_lookup = flags & BOOTSTRAP_PRIVILEGED_SERVER; |
199 | kern_return_t kr = 0; | |
5b0a4722 | 200 | mach_port_t puc; |
dcace88f A |
201 | |
202 | // We have to cast instance_id here because the MIG-generated method | |
203 | // doesn't expect a const parameter. | |
204 | if ((kr = vproc_mig_look_up2(bp, (char *)service_name, sp, &au_tok, target_pid, (unsigned char*)instance_id, flags)) != VPROC_ERR_TRY_PER_USER) { | |
ddbbfbc1 A |
205 | goto out; |
206 | } | |
eabd1701 | 207 | |
5b0a4722 | 208 | if ((kr = vproc_mig_lookup_per_user_context(bp, 0, &puc)) != 0) { |
ddbbfbc1 | 209 | goto out; |
5b0a4722 | 210 | } |
eabd1701 | 211 | |
dcace88f | 212 | kr = vproc_mig_look_up2(puc, (char *)service_name, sp, &au_tok, target_pid, (unsigned char*)instance_id, flags); |
5b0a4722 | 213 | mach_port_deallocate(mach_task_self(), puc); |
dcace88f | 214 | |
ddbbfbc1 | 215 | out: |
ddbbfbc1 A |
216 | if ((kr == 0) && privileged_server_lookup) { |
217 | uid_t server_euid; | |
eabd1701 | 218 | |
ddbbfbc1 A |
219 | /* |
220 | * The audit token magic is dependent on the per-user launchd | |
221 | * forwarding MIG requests to the root launchd when it cannot | |
222 | * find the answer locally. | |
223 | */ | |
eabd1701 | 224 | |
ddbbfbc1 A |
225 | /* This API should be in Libsystem, but is not */ |
226 | //audit_token_to_au32(au_tok, NULL, &server_euid, NULL, NULL, NULL, NULL, NULL, NULL); | |
eabd1701 | 227 | |
ddbbfbc1 | 228 | server_euid = au_tok.val[1]; |
eabd1701 | 229 | |
ddbbfbc1 A |
230 | if (server_euid) { |
231 | mach_port_deallocate(mach_task_self(), *sp); | |
dcace88f | 232 | *sp = MACH_PORT_NULL; |
ddbbfbc1 A |
233 | kr = BOOTSTRAP_NOT_PRIVILEGED; |
234 | } | |
235 | } | |
dcace88f | 236 | |
5b0a4722 A |
237 | return kr; |
238 | } | |
239 | ||
dcace88f A |
240 | kern_return_t |
241 | bootstrap_check_in3(mach_port_t bp, const name_t service_name, mach_port_t *sp, uuid_t instance_id, uint64_t flags) | |
242 | { | |
243 | return vproc_mig_check_in2(bp, (char *)service_name, sp, instance_id, flags); | |
244 | } | |
245 | ||
246 | kern_return_t | |
247 | bootstrap_get_root(mach_port_t bp, mach_port_t *root) | |
248 | { | |
249 | return vproc_mig_get_root_bootstrap(bp, root); | |
250 | } | |
251 | ||
5b0a4722 A |
252 | kern_return_t |
253 | bootstrap_status(mach_port_t bp, name_t service_name, bootstrap_status_t *service_active) | |
254 | { | |
ddbbfbc1 | 255 | kern_return_t kr; |
5b0a4722 A |
256 | mach_port_t p; |
257 | ||
ddbbfbc1 A |
258 | if ((kr = bootstrap_look_up(bp, service_name, &p))) { |
259 | return kr; | |
260 | } | |
261 | ||
262 | mach_port_deallocate(mach_task_self(), p); | |
263 | *service_active = BOOTSTRAP_STATUS_ACTIVE; | |
264 | ||
5b0a4722 A |
265 | if (bootstrap_check_in(bp, service_name, &p) == BOOTSTRAP_SUCCESS) { |
266 | mach_port_mod_refs(mach_task_self(), p, MACH_PORT_RIGHT_RECEIVE, -1); | |
267 | *service_active = BOOTSTRAP_STATUS_ON_DEMAND; | |
5b0a4722 A |
268 | } |
269 | ||
ddbbfbc1 | 270 | return BOOTSTRAP_SUCCESS; |
5b0a4722 A |
271 | } |
272 | ||
273 | kern_return_t | |
274 | bootstrap_info(mach_port_t bp, | |
ddbbfbc1 A |
275 | name_array_t *service_names, mach_msg_type_number_t *service_namesCnt, |
276 | name_array_t *service_jobs, mach_msg_type_number_t *service_jobsCnt, | |
277 | bootstrap_status_array_t *service_active, mach_msg_type_number_t *service_activeCnt, | |
278 | uint64_t flags) | |
5b0a4722 | 279 | { |
ddbbfbc1 | 280 | return vproc_mig_info(bp, service_names, service_namesCnt, service_jobs, service_jobsCnt, service_active, service_activeCnt, flags); |
5b0a4722 A |
281 | } |
282 | ||
283 | const char * | |
284 | bootstrap_strerror(kern_return_t r) | |
285 | { | |
286 | switch (r) { | |
287 | case BOOTSTRAP_SUCCESS: | |
288 | return "Success"; | |
289 | case BOOTSTRAP_NOT_PRIVILEGED: | |
290 | return "Permission denied"; | |
291 | case BOOTSTRAP_NAME_IN_USE: | |
292 | case BOOTSTRAP_SERVICE_ACTIVE: | |
293 | return "Service name already exists"; | |
294 | case BOOTSTRAP_UNKNOWN_SERVICE: | |
295 | return "Unknown service name"; | |
296 | case BOOTSTRAP_BAD_COUNT: | |
297 | return "Too many lookups were requested in one request"; | |
298 | case BOOTSTRAP_NO_MEMORY: | |
299 | return "Out of memory"; | |
300 | default: | |
301 | return mach_error_string(r); | |
302 | } | |
303 | } |