#include <mach/mach.h>
#include <mach/mach_error.h>
#include <syslog.h>
#include <string.h>
#include <bsm/audit.h>
#include <bsm/libbsm.h>
#include "bootstrap_internal.h"
#include "lists.h"
#include "bootstrap.h"
#ifndef ASSERT
#define ASSERT(p)
#endif
#ifndef NULL
#define NULL ((void *)0)
#endif NULL
#define bsstatus(servicep) \
(((servicep)->isActive) ? BOOTSTRAP_STATUS_ACTIVE : \
(((servicep)->server && (servicep)->server->servertype == DEMAND) ? \
BOOTSTRAP_STATUS_ON_DEMAND : BOOTSTRAP_STATUS_INACTIVE))
__private_extern__ kern_return_t
x_bootstrap_create_server(
mach_port_t bootstrapport,
cmd_t server_cmd,
uid_t server_uid,
boolean_t on_demand,
audit_token_t client_audit_token,
mach_port_t *server_portp)
{
server_t *serverp;
struct auditinfo audit_info;
bootstrap_info_t *bootstrap;
uid_t client_euid;
bootstrap = lookup_bootstrap_by_port(bootstrapport);
syslog(LOG_DEBUG, "Server create attempt: \"%s\" bootstrap %x",
server_cmd, bootstrapport);
if (!bootstrap || !active_bootstrap(bootstrap)) {
syslog(LOG_DEBUG, "Server create: \"%s\": invalid bootstrap %x",
server_cmd, bootstrapport);
return BOOTSTRAP_NOT_PRIVILEGED;
}
audit_token_to_au32(client_audit_token,
&audit_info.ai_auid,
&client_euid,
NULL ,
NULL ,
NULL ,
NULL ,
&audit_info.ai_asid,
&audit_info.ai_termid);
if (client_euid != 0 && client_euid != server_uid) {
syslog(LOG_NOTICE, "Server create: \"%s\": insufficient privilege for specified uid (euid-%d != requested-%d)",
server_cmd, client_euid, server_uid);
return BOOTSTRAP_NOT_PRIVILEGED;
}
serverp = new_server(
bootstrap,
server_cmd,
server_uid,
(on_demand) ? DEMAND : RESTARTABLE,
audit_info);
setup_server(serverp);
syslog(LOG_INFO, "New server %x in bootstrap %x: \"%s\"",
serverp->port, bootstrapport, server_cmd);
*server_portp = serverp->port;
return BOOTSTRAP_SUCCESS;
}
__private_extern__ kern_return_t
x_bootstrap_unprivileged(
mach_port_t bootstrapport,
mach_port_t *unprivportp)
{
bootstrap_info_t *bootstrap;
syslog(LOG_DEBUG, "Get unprivileged attempt for bootstrap %x", bootstrapport);
bootstrap = lookup_bootstrap_by_port(bootstrapport);
if (!bootstrap) {
syslog(LOG_DEBUG, "Get unprivileged: invalid bootstrap %x", bootstrapport);
return BOOTSTRAP_NOT_PRIVILEGED;
}
*unprivportp = bootstrap->bootstrap_port;
syslog(LOG_DEBUG, "Get unpriv bootstrap %x returned for bootstrap %x",
bootstrap->bootstrap_port, bootstrapport);
return BOOTSTRAP_SUCCESS;
}
__private_extern__ kern_return_t
x_bootstrap_check_in(
mach_port_t bootstrapport,
name_t servicename,
mach_port_t *serviceportp)
{
kern_return_t result;
mach_port_t previous;
service_t *servicep;
server_t *serverp;
bootstrap_info_t *bootstrap;
serverp = lookup_server_by_port(bootstrapport);
bootstrap = lookup_bootstrap_by_port(bootstrapport);
syslog(LOG_DEBUG, "Service checkin attempt for service %s bootstrap %x",
servicename, bootstrapport);
servicep = lookup_service_by_name(bootstrap, servicename);
if (servicep == NULL || servicep->port == MACH_PORT_NULL) {
syslog(LOG_DEBUG, "bootstrap_check_in service %s unknown%s", servicename,
forward_ok ? " forwarding" : "");
return forward_ok ?
bootstrap_check_in(
inherited_bootstrap_port,
servicename,
serviceportp) :
BOOTSTRAP_UNKNOWN_SERVICE;
}
if (servicep->server != NULL && servicep->server != serverp) {
syslog(LOG_DEBUG, "bootstrap_check_in service %s not privileged",
servicename);
return BOOTSTRAP_NOT_PRIVILEGED;
}
if (!canReceive(servicep->port)) {
ASSERT(servicep->isActive);
syslog(LOG_DEBUG, "bootstrap_check_in service %s already active",
servicename);
return BOOTSTRAP_SERVICE_ACTIVE;
}
syslog(LOG_DEBUG, "Checkin service %s for bootstrap %x", servicename,
bootstrap->bootstrap_port);
ASSERT(servicep->isActive == FALSE);
servicep->isActive = TRUE;
if (servicep->server != NULL_SERVER) {
serverp->activity++;
serverp->active_services++;
result = mach_port_request_notification(
mach_task_self(),
servicep->port,
MACH_NOTIFY_PORT_DESTROYED,
0,
backup_port,
MACH_MSG_TYPE_MAKE_SEND_ONCE,
&previous);
if (result != KERN_SUCCESS)
panic("mach_port_request_notification(): %s", mach_error_string(result));
} else {
servicep->servicetype = REGISTERED;
result = mach_port_request_notification(
mach_task_self(),
servicep->port,
MACH_NOTIFY_DEAD_NAME,
0,
notify_port,
MACH_MSG_TYPE_MAKE_SEND_ONCE,
&previous);
if (result != KERN_SUCCESS)
panic("mach_port_request_notification(): %s", mach_error_string(result));
else if (previous != MACH_PORT_NULL) {
syslog(LOG_DEBUG, "deallocating old notification port (%x) for checked in service %x",
previous, servicep->port);
result = mach_port_deallocate(
mach_task_self(),
previous);
if (result != KERN_SUCCESS)
panic("mach_port_deallocate(): %s", mach_error_string(result));
}
}
syslog(LOG_INFO, "Check-in service %x in bootstrap %x: %s",
servicep->port, servicep->bootstrap->bootstrap_port, servicep->name);
*serviceportp = servicep->port;
return BOOTSTRAP_SUCCESS;
}
__private_extern__ kern_return_t
x_bootstrap_register(
mach_port_t bootstrapport,
name_t servicename,
mach_port_t serviceport)
{
kern_return_t result;
service_t *servicep;
server_t *serverp;
bootstrap_info_t *bootstrap;
mach_port_t old_port;
syslog(LOG_DEBUG, "Register attempt for service %s port %x",
servicename, serviceport);
bootstrap = lookup_bootstrap_by_port(bootstrapport);
if (!bootstrap || !active_bootstrap(bootstrap))
return BOOTSTRAP_NOT_PRIVILEGED;
serverp = lookup_server_by_port(bootstrapport);
servicep = lookup_service_by_name(bootstrap, servicename);
if (servicep && servicep->server && servicep->server != serverp)
return BOOTSTRAP_NOT_PRIVILEGED;
if (servicep == NULL || servicep->bootstrap != bootstrap) {
servicep = new_service(bootstrap,
servicename,
serviceport,
ACTIVE,
REGISTERED,
NULL_SERVER);
syslog(LOG_DEBUG, "Registered new service %s", servicename);
} else {
if (servicep->isActive) {
syslog(LOG_DEBUG, "Register: service %s already active, port %x",
servicep->name, servicep->port);
ASSERT(!canReceive(servicep->port));
return BOOTSTRAP_SERVICE_ACTIVE;
}
old_port = servicep->port;
if (servicep->servicetype == DECLARED) {
servicep->servicetype = REGISTERED;
if (servicep->server) {
ASSERT(servicep->server == serverp);
ASSERT(active_server(serverp));
servicep->server = NULL_SERVER;
serverp->activity++;
}
result = mach_port_mod_refs(
mach_task_self(),
old_port,
MACH_PORT_RIGHT_RECEIVE,
-1);
if (result != KERN_SUCCESS)
panic("mach_port_mod_refs(): %s", mach_error_string(result));
}
result = mach_port_deallocate(
mach_task_self(),
old_port);
if (result != KERN_SUCCESS)
panic("mach_port_mod_refs(): %s", mach_error_string(result));
servicep->port = serviceport;
servicep->isActive = TRUE;
syslog(LOG_DEBUG, "Re-registered inactive service %x bootstrap %x: %s",
servicep->port, servicep->bootstrap->bootstrap_port, servicename);
}
result = mach_port_request_notification(
mach_task_self(),
serviceport,
MACH_NOTIFY_DEAD_NAME,
0,
notify_port,
MACH_MSG_TYPE_MAKE_SEND_ONCE,
&old_port);
if (result != KERN_SUCCESS) {
syslog(LOG_DEBUG, "Can't request notification on service %x bootstrap %x: %s",
service_port, servicep->bootstrap->bootstrap_port, "must be dead");
delete_service(servicep);
return BOOTSTRAP_SUCCESS;
} else if (old_port != MACH_PORT_NULL) {
syslog(LOG_DEBUG, "deallocating old notification port (%x) for service %x",
old_port, serviceport);
result = mach_port_deallocate(
mach_task_self(),
old_port);
if (result != KERN_SUCCESS)
panic("mach_port_deallocate(): %s", mach_error_string(result));
}
syslog(LOG_INFO, "Registered service %x bootstrap %x: %s",
servicep->port, servicep->bootstrap->bootstrap_port, servicep->name);
return BOOTSTRAP_SUCCESS;
}
__private_extern__ kern_return_t
x_bootstrap_look_up(
mach_port_t bootstrapport,
name_t servicename,
mach_port_t *serviceportp)
{
service_t *servicep;
bootstrap_info_t *bootstrap;
bootstrap = lookup_bootstrap_by_port(bootstrapport);
servicep = lookup_service_by_name(bootstrap, servicename);
if (servicep == NULL || servicep->port == MACH_PORT_NULL) {
if (forward_ok) {
syslog(LOG_DEBUG, "bootstrap_look_up service %s forwarding",
servicename);
return bootstrap_look_up(inherited_bootstrap_port,
servicename,
serviceportp);
} else {
syslog(LOG_DEBUG, "bootstrap_look_up service %s unknown",
servicename);
return BOOTSTRAP_UNKNOWN_SERVICE;
}
}
*serviceportp = servicep->port;
syslog(LOG_DEBUG, "Lookup returns port %x for service %s", servicep->port, servicep->name);
return BOOTSTRAP_SUCCESS;
}
__private_extern__ kern_return_t
x_bootstrap_look_up_array(
mach_port_t bootstrapport,
name_array_t servicenames,
unsigned int servicenames_cnt,
mach_port_array_t *serviceportsp,
unsigned int *serviceports_cnt,
boolean_t *allservices_known)
{
unsigned int i;
static mach_port_t service_ports[BOOTSTRAP_MAX_LOOKUP_COUNT];
if (servicenames_cnt > BOOTSTRAP_MAX_LOOKUP_COUNT)
return BOOTSTRAP_BAD_COUNT;
*serviceports_cnt = servicenames_cnt;
*allservices_known = TRUE;
for (i = 0; i < servicenames_cnt; i++) {
if ( x_bootstrap_look_up(bootstrapport,
servicenames[i],
&service_ports[i])
!= BOOTSTRAP_SUCCESS)
{
*allservices_known = FALSE;
service_ports[i] = MACH_PORT_NULL;
}
}
syslog(LOG_DEBUG, "bootstrap_look_up_array returns %d ports", servicenames_cnt);
*serviceportsp = service_ports;
return BOOTSTRAP_SUCCESS;
}
__private_extern__ kern_return_t
x_bootstrap_parent(
mach_port_t bootstrapport,
security_token_t sectoken,
mach_port_t *parentport)
{
bootstrap_info_t *bootstrap;
syslog(LOG_DEBUG, "Parent attempt for bootstrap %x", bootstrapport);
bootstrap = lookup_bootstrap_by_port(bootstrapport);
if (!bootstrap) {
syslog(LOG_DEBUG, "Parent attempt for bootstrap %x: invalid bootstrap",
bootstrapport);
return BOOTSTRAP_NOT_PRIVILEGED;
}
if (sectoken.val[0]) {
syslog(LOG_NOTICE, "Bootstrap parent for bootstrap %x: invalid security token (%d)",
bootstrapport, sectoken.val[0]);
return BOOTSTRAP_NOT_PRIVILEGED;
}
syslog(LOG_DEBUG, "Returning bootstrap parent %x for bootstrap %x",
bootstrap->parent->bootstrap_port, bootstrapport);
*parentport = bootstrap->parent->bootstrap_port;
return BOOTSTRAP_SUCCESS;
}
__private_extern__ kern_return_t
x_bootstrap_status(
mach_port_t bootstrapport,
name_t servicename,
bootstrap_status_t *serviceactivep)
{
service_t *servicep;
bootstrap_info_t *bootstrap;
bootstrap = lookup_bootstrap_by_port(bootstrapport);
servicep = lookup_service_by_name(bootstrap, servicename);
if (servicep == NULL) {
if (forward_ok) {
syslog(LOG_DEBUG, "bootstrap_status forwarding status, server %s",
servicename);
return bootstrap_status(inherited_bootstrap_port,
servicename,
serviceactivep);
} else {
syslog(LOG_DEBUG, "bootstrap_status service %s unknown",
servicename);
return BOOTSTRAP_UNKNOWN_SERVICE;
}
}
*serviceactivep = bsstatus(servicep);
syslog(LOG_DEBUG, "bootstrap_status server %s %sactive", servicename,
servicep->isActive ? "" : "in");
return BOOTSTRAP_SUCCESS;
}
__private_extern__ kern_return_t
x_bootstrap_info(
mach_port_t bootstrapport,
name_array_t *servicenamesp,
unsigned int *servicenames_cnt,
name_array_t *servernamesp,
unsigned int *servernames_cnt,
bootstrap_status_array_t *serviceactivesp,
unsigned int *serviceactives_cnt)
{
kern_return_t result;
unsigned int i, cnt;
service_t *servicep;
server_t *serverp;
bootstrap_info_t *bootstrap;
name_array_t service_names;
name_array_t server_names;
bootstrap_status_array_t service_actives;
bootstrap = lookup_bootstrap_by_port(bootstrapport);
for ( cnt = i = 0, servicep = services.next
; i < nservices
; servicep = servicep->next, i++)
{
if (lookup_service_by_name(bootstrap, servicep->name) == servicep)
{
cnt++;
}
}
result = vm_allocate(mach_task_self(),
(vm_address_t *)&service_names,
cnt * sizeof(service_names[0]),
ANYWHERE);
if (result != KERN_SUCCESS)
return BOOTSTRAP_NO_MEMORY;
result = vm_allocate(mach_task_self(),
(vm_address_t *)&server_names,
cnt * sizeof(server_names[0]),
ANYWHERE);
if (result != KERN_SUCCESS) {
(void)vm_deallocate(mach_task_self(),
(vm_address_t)service_names,
cnt * sizeof(service_names[0]));
return BOOTSTRAP_NO_MEMORY;
}
result = vm_allocate(mach_task_self(),
(vm_address_t *)&service_actives,
cnt * sizeof(service_actives[0]),
ANYWHERE);
if (result != KERN_SUCCESS) {
(void)vm_deallocate(mach_task_self(),
(vm_address_t)service_names,
cnt * sizeof(service_names[0]));
(void)vm_deallocate(mach_task_self(),
(vm_address_t)server_names,
cnt * sizeof(server_names[0]));
return BOOTSTRAP_NO_MEMORY;
}
for ( i = 0, servicep = services.next
; i < cnt
; servicep = servicep->next)
{
if ( lookup_service_by_name(bootstrap, servicep->name)
!= servicep)
continue;
strncpy(service_names[i],
servicep->name,
sizeof(service_names[0]));
service_names[i][sizeof(service_names[0]) - 1] = '\0';
if (servicep->server) {
serverp = servicep->server;
strncpy(server_names[i],
serverp->cmd,
sizeof(server_names[0]));
server_names[i][sizeof(server_names[0]) - 1] = '\0';
syslog(LOG_DEBUG, "bootstrap info service %s server %s %sactive",
servicep->name,
serverp->cmd, servicep->isActive ? "" : "in");
} else {
server_names[i][0] = '\0';
syslog(LOG_DEBUG, "bootstrap info service %s %sactive",
servicep->name, servicep->isActive ? "" : "in");
}
service_actives[i] = bsstatus(servicep);
i++;
}
*servicenamesp = service_names;
*servernamesp = server_names;
*serviceactivesp = service_actives;
*servicenames_cnt = *servernames_cnt = *serviceactives_cnt = cnt;
return BOOTSTRAP_SUCCESS;
}
__private_extern__ kern_return_t
x_bootstrap_subset(
mach_port_t bootstrapport,
mach_port_t requestorport,
mach_port_t *subsetportp)
{
kern_return_t result;
bootstrap_info_t *bootstrap;
bootstrap_info_t *subset;
mach_port_t new_bootstrapport;
mach_port_t previous;
syslog(LOG_DEBUG, "Subset create attempt: bootstrap %x, requestor: %x",
bootstrapport, requestorport);
bootstrap = lookup_bootstrap_by_port(bootstrapport);
if (!bootstrap || !active_bootstrap(bootstrap))
return BOOTSTRAP_NOT_PRIVILEGED;
result = mach_port_allocate(
mach_task_self(),
MACH_PORT_RIGHT_RECEIVE,
&new_bootstrapport);
if (result != KERN_SUCCESS)
panic("mach_port_allocate(): %s", mach_error_string(result));
result = mach_port_insert_right(
mach_task_self(),
new_bootstrapport,
new_bootstrapport,
MACH_MSG_TYPE_MAKE_SEND);
if (result != KERN_SUCCESS)
panic("failed to insert send right(): %s", mach_error_string(result));
result = mach_port_insert_member(
mach_task_self(),
new_bootstrapport,
bootstrap_port_set);
if (result != KERN_SUCCESS)
panic("port_set_add(): %s", mach_error_string(result));
subset = new_bootstrap(bootstrap, new_bootstrapport, requestorport);
result = mach_port_request_notification(
mach_task_self(),
requestorport,
MACH_NOTIFY_DEAD_NAME,
0,
notify_port,
MACH_MSG_TYPE_MAKE_SEND_ONCE,
&previous);
if (result != KERN_SUCCESS) {
syslog(LOG_ERR, "mach_port_request_notification(): %s", mach_error_string(result));
mach_port_deallocate(mach_task_self(), requestorport);
subset->requestor_port = MACH_PORT_NULL;
deactivate_bootstrap(subset);
} else if (previous != MACH_PORT_NULL) {
syslog(LOG_DEBUG, "deallocating old notification port (%x) for requestor %x",
previous, requestorport);
result = mach_port_deallocate(
mach_task_self(),
previous);
if (result != KERN_SUCCESS)
panic("mach_port_deallocate(): %s", mach_error_string(result));
}
syslog(LOG_INFO, "Created bootstrap subset %x parent %x requestor %x",
new_bootstrapport, bootstrapport, requestorport);
*subsetportp = new_bootstrapport;
return BOOTSTRAP_SUCCESS;
}
__private_extern__ kern_return_t
x_bootstrap_create_service(
mach_port_t bootstrapport,
name_t servicename,
mach_port_t *serviceportp)
{
server_t *serverp;
service_t *servicep;
bootstrap_info_t *bootstrap;
kern_return_t result;
bootstrap = lookup_bootstrap_by_port(bootstrapport);
if (!bootstrap || !active_bootstrap(bootstrap))
return BOOTSTRAP_NOT_PRIVILEGED;
syslog(LOG_DEBUG, "Service creation attempt for service %s bootstrap %x",
servicename, bootstrapport);
servicep = lookup_service_by_name(bootstrap, servicename);
if (servicep) {
syslog(LOG_DEBUG, "Service creation attempt for service %s failed, "
"service already exists", servicename);
return BOOTSTRAP_NAME_IN_USE;
}
serverp = lookup_server_by_port(bootstrapport);
result = mach_port_allocate(mach_task_self(),
MACH_PORT_RIGHT_RECEIVE,
serviceportp);
if (result != KERN_SUCCESS)
panic("port_allocate(): %s", mach_error_string(result));
result = mach_port_insert_right(mach_task_self(),
*serviceportp,
*serviceportp,
MACH_MSG_TYPE_MAKE_SEND);
if (result != KERN_SUCCESS)
panic("failed to insert send right(): %s", mach_error_string(result));
if (serverp)
serverp->activity++;
servicep = new_service(bootstrap,
servicename,
*serviceportp,
!ACTIVE,
DECLARED,
serverp);
syslog(LOG_INFO, "Created new service %x in bootstrap %x: %s",
servicep->port, bootstrap->bootstrap_port, servicename);
return BOOTSTRAP_SUCCESS;
}