#include <servers/bootstrap.h>
#include <sysexits.h>
#include "configd.h"
#include "configd_server.h"
#include "notify_server.h"
#include "session.h"
#include "notify.h"
extern struct rpc_subsystem _config_subsystem;
extern boolean_t config_server(mach_msg_header_t *, mach_msg_header_t *);
CFMachPortRef configd_port;
boolean_t
config_demux(mach_msg_header_t *request, mach_msg_header_t *reply)
{
boolean_t processed = FALSE;
mach_msg_format_0_trailer_t *trailer;
if (!processed &&
(request->msgh_id >= _config_subsystem.start && request->msgh_id < _config_subsystem.end)) {
serverSessionRef thisSession;
thisSession = getSession(request->msgh_local_port);
if (thisSession) {
trailer = (mach_msg_security_trailer_t *)((vm_offset_t)request +
round_msg(request->msgh_size));
if ((trailer->msgh_trailer_type == MACH_MSG_TRAILER_FORMAT_0) &&
(trailer->msgh_trailer_size >= MACH_MSG_TRAILER_FORMAT_0_SIZE)) {
thisSession->callerEUID = trailer->msgh_sender.val[0];
thisSession->callerEGID = trailer->msgh_sender.val[1];
SCDLog(LOG_DEBUG, CFSTR("caller has eUID = %d, eGID = %d"),
thisSession->callerEUID,
thisSession->callerEGID);
} else {
static boolean_t warned = FALSE;
if (!warned) {
SCDLog(LOG_WARNING, CFSTR("caller's credentials not available."));
warned = TRUE;
}
thisSession->callerEUID = 0;
thisSession->callerEGID = 0;
}
}
processed = config_server(request, reply);
}
if (!processed &&
(request->msgh_id >= MACH_NOTIFY_FIRST && request->msgh_id < MACH_NOTIFY_LAST)) {
processed = notify_server(request, reply);
}
if (!processed) {
SCDLog(LOG_WARNING, CFSTR("unknown message received"));
exit (EX_OSERR);
}
return processed;
}
void
configdCallback(CFMachPortRef port, void *msg, CFIndex size, void *info)
{
mig_reply_error_t *bufRequest = msg;
mig_reply_error_t *bufReply = CFAllocatorAllocate(NULL, _config_subsystem.maxsize, 0);
mach_msg_return_t mr;
int options;
(void) config_demux(&bufRequest->Head, &bufReply->Head);
if (!(bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) && (bufReply->RetCode != KERN_SUCCESS)) {
if (bufReply->RetCode == MIG_NO_REPLY) {
CFAllocatorDeallocate(NULL, bufReply);
return;
}
bufRequest->Head.msgh_remote_port = MACH_PORT_NULL;
mach_msg_destroy(&bufRequest->Head);
}
if (bufReply->Head.msgh_remote_port == MACH_PORT_NULL) {
if (bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) {
mach_msg_destroy(&bufReply->Head);
}
CFAllocatorDeallocate(NULL, bufReply);
return;
}
options = MACH_SEND_MSG;
if (MACH_MSGH_BITS_REMOTE(bufReply->Head.msgh_bits) == MACH_MSG_TYPE_MOVE_SEND_ONCE) {
options |= MACH_SEND_TIMEOUT;
}
mr = mach_msg(&bufReply->Head,
options,
bufReply->Head.msgh_size,
0,
MACH_PORT_NULL,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
switch (mr) {
case MACH_SEND_INVALID_DEST:
case MACH_SEND_TIMED_OUT:
mach_msg_destroy(&bufReply->Head);
break;
default :
break;
}
CFAllocatorDeallocate(NULL, bufReply);
}
boolean_t
server_active()
{
kern_return_t status;
mach_port_t bootstrap_port;
boolean_t active;
status = task_get_bootstrap_port(mach_task_self(), &bootstrap_port);
if (status != KERN_SUCCESS) {
fprintf(stderr, "task_get_bootstrap_port(): %s\n",
mach_error_string(status));
exit (EX_UNAVAILABLE);
}
status = bootstrap_status(bootstrap_port, SCD_SERVER, &active);
switch (status) {
case BOOTSTRAP_SUCCESS :
if (active) {
fprintf(stderr, "configd: '%s' server already active\n",
SCD_SERVER);
return TRUE;
}
break;
case BOOTSTRAP_UNKNOWN_SERVICE :
break;
default :
fprintf(stderr, "bootstrap_status(): %s\n",
mach_error_string(status));
exit (EX_UNAVAILABLE);
}
return FALSE;
}
void
server_init()
{
kern_return_t status;
mach_port_t bootstrap_port;
boolean_t active;
CFRunLoopSourceRef rls;
status = task_get_bootstrap_port(mach_task_self(), &bootstrap_port);
if (status != KERN_SUCCESS) {
SCDLog(LOG_DEBUG, CFSTR("task_get_bootstrap_port(): %s"), mach_error_string(status));
exit (EX_UNAVAILABLE);
}
status = bootstrap_status(bootstrap_port, SCD_SERVER, &active);
switch (status) {
case BOOTSTRAP_SUCCESS :
if (active) {
SCDLog(LOG_DEBUG, CFSTR("\"%s\" is currently active, exiting."), SCD_SERVER);
exit (EX_UNAVAILABLE);
}
break;
case BOOTSTRAP_UNKNOWN_SERVICE :
break;
default :
fprintf(stderr, "bootstrap_status(): %s\n", mach_error_string(status));
exit (EX_UNAVAILABLE);
}
configd_port = CFMachPortCreate(NULL, configdCallback, NULL, NULL);
rls = CFMachPortCreateRunLoopSource(NULL, configd_port, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, CFSTR("locked"));
CFRelease(rls);
(void) addSession(configd_port);
SCDLog(LOG_DEBUG, CFSTR("Registering service \"%s\""), SCD_SERVER);
status = bootstrap_register(bootstrap_port, SCD_SERVER, CFMachPortGetPort(configd_port));
switch (status) {
case BOOTSTRAP_SUCCESS :
break;
case BOOTSTRAP_NOT_PRIVILEGED :
SCDLog(LOG_ERR, CFSTR("bootstrap_register(): bootstrap not privileged"));
exit (EX_OSERR);
case BOOTSTRAP_SERVICE_ACTIVE :
SCDLog(LOG_ERR, CFSTR("bootstrap_register(): bootstrap service active"));
exit (EX_OSERR);
default :
SCDLog(LOG_ERR, CFSTR("bootstrap_register(): %s"), mach_error_string(status));
exit (EX_OSERR);
}
return;
}
void
server_loop()
{
CFStringRef rlMode;
int rlStatus;
while (TRUE) {
boolean_t isLocked = SCDOptionGet(NULL, kSCDOptionIsLocked);
_showMachPortStatus();
rlMode = isLocked ? CFSTR("locked") : kCFRunLoopDefaultMode;
rlStatus = CFRunLoopRunInMode(rlMode, 1.0e10, TRUE);
pushNotifications();
}
}