mach_server_utilities.c [plain text]
#include <CoreFoundation/CoreFoundation.h>
#include <Kerberos/KerberosDebug.h>
#include <mach/mach.h>
#include <mach/boolean.h>
#include <mach/mach_error.h>
#include <mach/notify.h>
#include <servers/bootstrap.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <sys/param.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <Kerberos/mach_server_utilities.h>
#include <Kerberos/mach_client_utilities.h>
#include "notifyServer.h"
static mach_port_t gBootPort = MACH_PORT_NULL;
static mach_port_t gServicePort = MACH_PORT_NULL;
static mach_port_t gNotifyPort = MACH_PORT_NULL;
static mach_port_t gServerPortSet = MACH_PORT_NULL;
static boolean_t gReadyToQuit = FALSE;
static boolean_t (*gServerDemuxProc)(mach_msg_header_t *, mach_msg_header_t *);
static char gServiceName [kServiceNameMaxLength];
#pragma mark -
mach_port_t
mach_server_get_server_port ()
{
return gServicePort;
}
#pragma mark -
static kern_return_t
mach_server_setup_ports (void)
{
kern_return_t err = KERN_SUCCESS;
mach_port_t previousNotifyPort = MACH_PORT_NULL;
if (!err) {
err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_PORT_SET, &gServerPortSet);
}
if (!err) {
err = mach_port_move_member (mach_task_self (), gServicePort, gServerPortSet);
}
if (!err) {
err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, &gNotifyPort);
}
if (!err) {
err = mach_port_request_notification (mach_task_self (), gServicePort, MACH_NOTIFY_NO_SENDERS, true,
gNotifyPort, MACH_MSG_TYPE_MAKE_SEND_ONCE, &previousNotifyPort);
dprintf ("requesting notification for no senders of %x returned '%s', err = %d\n",
gServicePort, mach_error_string (err), err);
}
if (!err) {
err = mach_port_move_member (mach_task_self (), gNotifyPort, gServerPortSet);
}
return KerberosIPCError_ (err);
}
static kern_return_t
mach_server_cleanup_ports (void)
{
kern_return_t err = KERN_SUCCESS;
mach_port_t previousNotifyPort = MACH_PORT_NULL;
if (gServicePort != MACH_PORT_NULL) {
err = mach_port_request_notification (mach_task_self (), gServicePort, MACH_NOTIFY_NO_SENDERS,
true, MACH_PORT_NULL, MACH_MSG_TYPE_MAKE_SEND_ONCE,
&previousNotifyPort);
dprintf ("removing notification for no senders of %x returned '%s', err = %d\n",
previousNotifyPort, mach_error_string (err), err);
}
if (gNotifyPort != MACH_PORT_NULL) {
mach_port_deallocate (mach_task_self (), gNotifyPort);
gNotifyPort = MACH_PORT_NULL;
}
if (gServerPortSet != MACH_PORT_NULL) {
mach_port_deallocate (mach_task_self (), gServerPortSet);
gServerPortSet = MACH_PORT_NULL;
}
return KerberosIPCError_ (err);
}
kern_return_t
mach_server_run_server (boolean_t (*inDemuxProc)(mach_msg_header_t *, mach_msg_header_t *))
{
kern_return_t err = KERN_SUCCESS;
boolean_t active = false;
if (!err && (geteuid () == 0)) {
uid_t newUID = LoginSessionGetSecurityAgentUID ();
if (setuid (newUID) < 0) {
dprintf ("%s: setuid(%d) failed (euid is %d)", __FUNCTION__, newUID, geteuid ());
}
}
if (!err) {
gServerDemuxProc = inDemuxProc;
err = ENOMEM; CFBundleRef mainBundle = CFBundleGetMainBundle ();
if (mainBundle != NULL) {
CFStringRef mainBundleID = CFBundleGetIdentifier (mainBundle);
if (mainBundleID != NULL) {
if (CFStringGetCString (mainBundleID, gServiceName, kServiceNameMaxLength,
kCFStringEncodingASCII) == TRUE) {
err = KERN_SUCCESS;
}
}
}
}
if (!err) {
err = task_get_bootstrap_port (mach_task_self (), &gBootPort);
dprintf ("task_get_bootstrap_port(): port is %x (err = %d '%s')",
gBootPort, err, mach_error_string (err));
}
if (!err) {
err = bootstrap_status (gBootPort, gServiceName, &active);
dprintf ("bootstrap_status(%d, '%s'): returned state %d (err = %d '%s')",
gBootPort, gServiceName, active, err, mach_error_string (err));
if (!err && (active == BOOTSTRAP_STATUS_ACTIVE)) { err = BOOTSTRAP_NAME_IN_USE; }
if (!err && (active == BOOTSTRAP_STATUS_INACTIVE)) { err = BOOTSTRAP_UNKNOWN_SERVICE; }
}
if (!err) {
err = bootstrap_check_in (gBootPort, (char *) gServiceName, &gServicePort);
dprintf ("bootstrap_check_in('%s'): port is %d (err = %d '%s')",
gServiceName, gServicePort, err, mach_error_string (err));
}
if (!err) {
if (bootstrap_status (gBootPort, gServiceName, &active) == KERN_SUCCESS) {
dprintf ("'%s' state is now %d", gServiceName, active);
}
}
if (!err) {
err = mach_server_setup_ports ();
}
if (!err) {
dprintf ("\"%s\": starting up. ServicePort = %x, BootstrapPort = %x\n",
gServiceName, gServicePort, gBootPort);
}
while (!err && !gReadyToQuit) {
err = mach_msg_server_once (mach_server_demux, kMachIPCMaxMsgSize, gServerPortSet, MACH_MSG_OPTION_NONE);
}
mach_server_cleanup_ports ();
return KerberosIPCError_ (err);
}
#pragma mark -
boolean_t
mach_server_quit_self ()
{
dprintf ("mach_server_quit_self(): quitting...");
gReadyToQuit = true;
return gReadyToQuit;
}
#pragma mark -
boolean_t
mach_server_demux (mach_msg_header_t *request, mach_msg_header_t *reply)
{
if (mach_notify_server (request, reply) != false) {
return true;
} else {
return gServerDemuxProc (request, reply);
}
return false;
}
#pragma mark -
kern_return_t
do_mach_notify_port_deleted (mach_port_t notify, mach_port_name_t name)
{
dprintf ("%s: Received MACH_NOTIFY_PORT_DELETED... quitting self\n", gServiceName);
mach_server_quit_self ();
return KERN_SUCCESS;
}
kern_return_t
do_mach_notify_port_destroyed (mach_port_t notify, mach_port_t rights)
{
dprintf ("%s: Received MACH_NOTIFY_PORT_DESTROYED... quitting self\n", gServiceName);
mach_server_quit_self ();
return KERN_SUCCESS;
}
kern_return_t
do_mach_notify_no_senders (mach_port_t notify, mach_port_mscount_t mscount)
{
dprintf ("%s: Received MACH_NOTIFY_NO_SENDERS... quitting self\n", gServiceName);
mach_server_quit_self ();
return KERN_SUCCESS;
}
kern_return_t
do_mach_notify_send_once (mach_port_t notify)
{
dprintf ("%s: Received MACH_NOTIFY_SEND_ONCE\n", gServiceName);
return KERN_SUCCESS;
}
kern_return_t
do_mach_notify_dead_name (mach_port_t notify, mach_port_name_t name)
{
dprintf ("%s: Received MACH_NOTIFY_DEAD_NAME... quitting self\n", gServiceName);
mach_server_quit_self ();
return KERN_SUCCESS;
}