]>
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> | |
35 | ||
36 | #include "protocol_vproc.h" | |
37 | ||
38 | kern_return_t | |
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) | |
40 | { | |
ddbbfbc1 A |
41 | kern_return_t kr; |
42 | ||
43 | kr = vproc_mig_create_server(bp, server_cmd, server_uid, on_demand, server_port); | |
44 | ||
45 | if (kr == VPROC_ERR_TRY_PER_USER) { | |
46 | mach_port_t puc; | |
47 | ||
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); | |
51 | } | |
52 | } | |
53 | ||
54 | return kr; | |
5b0a4722 A |
55 | } |
56 | ||
57 | kern_return_t | |
58 | bootstrap_subset(mach_port_t bp, mach_port_t requestor_port, mach_port_t *subset_port) | |
59 | { | |
60 | return vproc_mig_subset(bp, requestor_port, subset_port); | |
61 | } | |
62 | ||
63 | kern_return_t | |
64 | bootstrap_unprivileged(mach_port_t bp, mach_port_t *unpriv_port) | |
65 | { | |
66 | kern_return_t kr; | |
67 | ||
68 | *unpriv_port = MACH_PORT_NULL; | |
69 | ||
70 | kr = mach_port_mod_refs(mach_task_self(), bp, MACH_PORT_RIGHT_SEND, 1); | |
71 | ||
72 | if (kr == KERN_SUCCESS) { | |
73 | *unpriv_port = bp; | |
74 | } | |
75 | ||
76 | return kr; | |
77 | } | |
78 | ||
79 | kern_return_t | |
80 | bootstrap_parent(mach_port_t bp, mach_port_t *parent_port) | |
81 | { | |
82 | return vproc_mig_parent(bp, parent_port); | |
83 | } | |
84 | ||
5b0a4722 A |
85 | kern_return_t |
86 | bootstrap_register(mach_port_t bp, name_t service_name, mach_port_t sp) | |
87 | { | |
88 | return bootstrap_register2(bp, service_name, sp, 0); | |
89 | } | |
90 | ||
91 | kern_return_t | |
92 | bootstrap_register2(mach_port_t bp, name_t service_name, mach_port_t sp, uint64_t flags) | |
93 | { | |
94 | kern_return_t kr = vproc_mig_register2(bp, service_name, sp, flags); | |
95 | ||
96 | if (kr == VPROC_ERR_TRY_PER_USER) { | |
97 | mach_port_t puc; | |
98 | ||
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); | |
102 | } | |
103 | } | |
104 | ||
105 | return kr; | |
106 | } | |
107 | ||
108 | kern_return_t | |
109 | bootstrap_create_service(mach_port_t bp, name_t service_name, mach_port_t *sp) | |
110 | { | |
ddbbfbc1 A |
111 | kern_return_t kr; |
112 | ||
113 | if ((kr = bootstrap_check_in(bp, service_name, sp))) { | |
114 | return kr; | |
115 | } | |
116 | ||
117 | if ((kr = mach_port_mod_refs(mach_task_self(), *sp, MACH_PORT_RIGHT_RECEIVE, -1))) { | |
118 | return kr; | |
119 | } | |
120 | ||
121 | return bootstrap_look_up(bp, service_name, sp); | |
5b0a4722 A |
122 | } |
123 | ||
124 | kern_return_t | |
ddbbfbc1 | 125 | bootstrap_check_in(mach_port_t bp, const name_t service_name, mach_port_t *sp) |
5b0a4722 | 126 | { |
ddbbfbc1 | 127 | return vproc_mig_check_in2(bp, (char *)service_name, sp, 0); |
5b0a4722 A |
128 | } |
129 | ||
130 | kern_return_t | |
ddbbfbc1 | 131 | bootstrap_check_in2(mach_port_t bp, const name_t service_name, mach_port_t *sp, uint64_t flags) |
5b0a4722 | 132 | { |
ddbbfbc1 A |
133 | return vproc_mig_check_in2(bp, (char *)service_name, sp, flags); |
134 | } | |
135 | ||
136 | kern_return_t | |
137 | bootstrap_look_up_per_user(mach_port_t bp, const name_t service_name, uid_t target_user, mach_port_t *sp) | |
138 | { | |
139 | audit_token_t au_tok; | |
5b0a4722 A |
140 | kern_return_t kr; |
141 | mach_port_t puc; | |
142 | ||
ddbbfbc1 | 143 | /* See rdar://problem/4890134. */ |
5b0a4722 A |
144 | |
145 | if ((kr = vproc_mig_lookup_per_user_context(bp, target_user, &puc)) != 0) { | |
146 | return kr; | |
147 | } | |
148 | ||
ddbbfbc1 A |
149 | if( !service_name ) { |
150 | *sp = puc; | |
151 | } else { | |
152 | kr = vproc_mig_look_up2(puc, (char *)service_name, sp, &au_tok, 0, 0); | |
153 | mach_port_deallocate(mach_task_self(), puc); | |
154 | } | |
5b0a4722 A |
155 | |
156 | return kr; | |
157 | } | |
158 | ||
ddbbfbc1 A |
159 | kern_return_t |
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) | |
161 | { | |
162 | mach_msg_type_number_t junk = 0; | |
163 | return vproc_mig_lookup_children(bp, children, &junk, names, n_children, properties, &junk); | |
164 | } | |
5b0a4722 A |
165 | |
166 | kern_return_t | |
ddbbfbc1 | 167 | bootstrap_look_up(mach_port_t bp, const name_t service_name, mach_port_t *sp) |
5b0a4722 A |
168 | { |
169 | return bootstrap_look_up2(bp, service_name, sp, 0, 0); | |
170 | } | |
171 | ||
172 | kern_return_t | |
ddbbfbc1 | 173 | bootstrap_look_up2(mach_port_t bp, const name_t service_name, mach_port_t *sp, pid_t target_pid, uint64_t flags) |
5b0a4722 | 174 | { |
ddbbfbc1 A |
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; | |
5b0a4722 | 183 | mach_port_t puc; |
ddbbfbc1 A |
184 | |
185 | pthread_mutex_lock(&bslu2_lock); | |
186 | ||
187 | if (per_pid_lookup || privileged_server_lookup) { | |
188 | goto skip_cache; | |
5b0a4722 | 189 | } |
ddbbfbc1 A |
190 | |
191 | if (prev_sp) { | |
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)) { | |
194 | *sp = prev_sp; | |
195 | goto out; | |
196 | } else { | |
197 | mach_port_deallocate(mach_task_self(), prev_sp); | |
198 | prev_sp = 0; | |
199 | } | |
200 | } | |
201 | ||
202 | skip_cache: | |
203 | if ((kr = vproc_mig_look_up2(bp, (char *)service_name, sp, &au_tok, target_pid, flags)) != VPROC_ERR_TRY_PER_USER) { | |
204 | goto out; | |
205 | } | |
206 | ||
5b0a4722 | 207 | if ((kr = vproc_mig_lookup_per_user_context(bp, 0, &puc)) != 0) { |
ddbbfbc1 | 208 | goto out; |
5b0a4722 | 209 | } |
ddbbfbc1 A |
210 | |
211 | kr = vproc_mig_look_up2(puc, (char *)service_name, sp, &au_tok, target_pid, flags); | |
5b0a4722 | 212 | mach_port_deallocate(mach_task_self(), puc); |
ddbbfbc1 A |
213 | |
214 | out: | |
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 */ | |
217 | prev_bp = bp; | |
218 | prev_sp = *sp; | |
219 | strlcpy(prev_name, service_name, sizeof(name_t)); | |
220 | } | |
221 | ||
222 | if ((kr == 0) && privileged_server_lookup) { | |
223 | uid_t server_euid; | |
224 | ||
225 | /* | |
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. | |
229 | */ | |
230 | ||
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); | |
233 | ||
234 | server_euid = au_tok.val[1]; | |
235 | ||
236 | if (server_euid) { | |
237 | mach_port_deallocate(mach_task_self(), *sp); | |
238 | kr = BOOTSTRAP_NOT_PRIVILEGED; | |
239 | } | |
240 | } | |
241 | /* If performance becomes a problem, we should restructure this. */ | |
242 | pthread_mutex_unlock(&bslu2_lock); | |
243 | ||
5b0a4722 A |
244 | return kr; |
245 | } | |
246 | ||
247 | kern_return_t | |
248 | bootstrap_status(mach_port_t bp, name_t service_name, bootstrap_status_t *service_active) | |
249 | { | |
ddbbfbc1 | 250 | kern_return_t kr; |
5b0a4722 A |
251 | mach_port_t p; |
252 | ||
ddbbfbc1 A |
253 | if ((kr = bootstrap_look_up(bp, service_name, &p))) { |
254 | return kr; | |
255 | } | |
256 | ||
257 | mach_port_deallocate(mach_task_self(), p); | |
258 | *service_active = BOOTSTRAP_STATUS_ACTIVE; | |
259 | ||
5b0a4722 A |
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; | |
5b0a4722 A |
263 | } |
264 | ||
ddbbfbc1 | 265 | return BOOTSTRAP_SUCCESS; |
5b0a4722 A |
266 | } |
267 | ||
268 | kern_return_t | |
269 | bootstrap_info(mach_port_t bp, | |
ddbbfbc1 A |
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, | |
273 | uint64_t flags) | |
5b0a4722 | 274 | { |
ddbbfbc1 | 275 | return vproc_mig_info(bp, service_names, service_namesCnt, service_jobs, service_jobsCnt, service_active, service_activeCnt, flags); |
5b0a4722 A |
276 | } |
277 | ||
278 | const char * | |
279 | bootstrap_strerror(kern_return_t r) | |
280 | { | |
281 | switch (r) { | |
282 | case BOOTSTRAP_SUCCESS: | |
283 | return "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"; | |
295 | default: | |
296 | return mach_error_string(r); | |
297 | } | |
298 | } |