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" 22#include "launch.h" 23#include "launch_priv.h" 24#include "bootstrap.h" 25#include "bootstrap_priv.h" 26#include "vproc.h" 27#include "vproc_priv.h" 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#include <stdlib.h> 36 37#include "job.h" 38 39void 40bootstrap_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 48kern_return_t 49bootstrap_create_server(mach_port_t bp, cmd_t server_cmd, uid_t server_uid, boolean_t on_demand, mach_port_t *server_port) 50{ 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; 65} 66 67kern_return_t 68bootstrap_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 73kern_return_t 74bootstrap_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 89kern_return_t 90bootstrap_parent(mach_port_t bp, mach_port_t *parent_port) 91{ 92 return vproc_mig_parent(bp, parent_port); 93} 94 95kern_return_t 96bootstrap_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 101kern_return_t 102bootstrap_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 118kern_return_t 119bootstrap_create_service(mach_port_t bp, name_t service_name, mach_port_t *sp) 120{ 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); 132} 133 134kern_return_t 135bootstrap_check_in(mach_port_t bp, const name_t service_name, mach_port_t *sp) 136{ 137 uuid_t junk; 138 (void)bzero(junk, sizeof(junk)); 139 return vproc_mig_check_in2(bp, (char *)service_name, sp, junk, 0); 140} 141 142kern_return_t 143bootstrap_check_in2(mach_port_t bp, const name_t service_name, mach_port_t *sp, uint64_t flags) 144{ 145 uuid_t junk; 146 (void)bzero(junk, sizeof(junk)); 147 return vproc_mig_check_in2(bp, (char *)service_name, sp, junk, flags); 148} 149 150kern_return_t 151bootstrap_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; 154 kern_return_t kr; 155 mach_port_t puc; 156 157 /* See rdar://problem/4890134. */ 158 159 if ((kr = vproc_mig_lookup_per_user_context(bp, target_user, &puc)) != 0) { 160 return kr; 161 } 162 163 if (!service_name) { 164 *sp = puc; 165 } else { 166 uuid_t junk; 167 kr = vproc_mig_look_up2(puc, (char *)service_name, sp, &au_tok, 0, junk, 0); 168 mach_port_deallocate(mach_task_self(), puc); 169 } 170 171 return kr; 172} 173 174kern_return_t 175bootstrap_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} 180 181kern_return_t 182bootstrap_look_up(mach_port_t bp, const name_t service_name, mach_port_t *sp) 183{ 184 return bootstrap_look_up2(bp, service_name, sp, 0, 0); 185} 186 187kern_return_t 188bootstrap_look_up2(mach_port_t bp, const name_t service_name, mach_port_t *sp, pid_t target_pid, uint64_t flags) 189{ 190 uuid_t instance_id; 191 return bootstrap_look_up3(bp, service_name, sp, target_pid, instance_id, flags); 192} 193 194kern_return_t 195bootstrap_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{ 197 audit_token_t au_tok; 198 bool privileged_server_lookup = flags & BOOTSTRAP_PRIVILEGED_SERVER; 199 kern_return_t kr = 0; 200 mach_port_t puc; 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) { 205 goto out; 206 } 207 208 if ((kr = vproc_mig_lookup_per_user_context(bp, 0, &puc)) != 0) { 209 goto out; 210 } 211 212 kr = vproc_mig_look_up2(puc, (char *)service_name, sp, &au_tok, target_pid, (unsigned char*)instance_id, flags); 213 mach_port_deallocate(mach_task_self(), puc); 214 215out: 216 if ((kr == 0) && privileged_server_lookup) { 217 uid_t server_euid; 218 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 */ 224 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); 227 228 server_euid = au_tok.val[1]; 229 230 if (server_euid) { 231 mach_port_deallocate(mach_task_self(), *sp); 232 *sp = MACH_PORT_NULL; 233 kr = BOOTSTRAP_NOT_PRIVILEGED; 234 } 235 } 236 237 return kr; 238} 239 240kern_return_t 241bootstrap_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 246kern_return_t 247bootstrap_get_root(mach_port_t bp, mach_port_t *root) 248{ 249 return vproc_mig_get_root_bootstrap(bp, root); 250} 251 252kern_return_t 253bootstrap_status(mach_port_t bp, name_t service_name, bootstrap_status_t *service_active) 254{ 255 kern_return_t kr; 256 mach_port_t p; 257 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 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; 268 } 269 270 return BOOTSTRAP_SUCCESS; 271} 272 273kern_return_t 274bootstrap_info(mach_port_t bp, 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) 279{ 280 return vproc_mig_info(bp, service_names, service_namesCnt, service_jobs, service_jobsCnt, service_active, service_activeCnt, flags); 281} 282 283const char * 284bootstrap_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} 304