blob: 273419bc8b8a78538598571dacdb14369f640573 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "sandbox/mac/xpc_message_server.h"
#include <bsm/libbsm.h>
#include <string>
#include "base/mac/mach_logging.h"
#include "base/strings/stringprintf.h"
#include "sandbox/mac/xpc.h"
namespace sandbox {
XPCMessageServer::XPCMessageServer(MessageDemuxer* demuxer,
mach_port_t server_receive_right)
: demuxer_(demuxer),
server_port_(server_receive_right),
reply_message_(NULL) {}
XPCMessageServer::~XPCMessageServer() {
}
bool XPCMessageServer::Initialize() {
// Allocate a port for use as a new server port if one was not passed to the
// constructor.
if (!server_port_.is_valid()) {
mach_port_t port;
kern_return_t kr;
if ((kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE,
&port)) != KERN_SUCCESS) {
MACH_LOG(ERROR, kr) << "Failed to allocate new server port.";
return false;
}
server_port_.reset(port);
}
std::string label = base::StringPrintf(
"org.chromium.sandbox.XPCMessageServer.%p", demuxer_);
dispatch_source_.reset(new base::DispatchSourceMach(
label.c_str(), server_port_.get(), ^{ ReceiveMessage(); }));
dispatch_source_->Resume();
return true;
}
void XPCMessageServer::Shutdown() {
dispatch_source_.reset();
}
pid_t XPCMessageServer::GetMessageSenderPID(IPCMessage request) {
audit_token_t token;
xpc_dictionary_get_audit_token(request.xpc, &token);
// TODO(rsesek): In the 10.7 SDK, there's audit_token_to_pid().
pid_t sender_pid;
audit_token_to_au32(token,
NULL, NULL, NULL, NULL, NULL, &sender_pid, NULL, NULL);
return sender_pid;
}
IPCMessage XPCMessageServer::CreateReply(IPCMessage request) {
if (!reply_message_)
reply_message_ = xpc_dictionary_create_reply(request.xpc);
IPCMessage reply;
reply.xpc = reply_message_;
return reply;
}
bool XPCMessageServer::SendReply(IPCMessage reply) {
if (!reply.xpc)
return false;
int rv = xpc_pipe_routine_reply(reply.xpc);
if (rv) {
LOG(ERROR) << "Failed to xpc_pipe_routine_reply(): " << rv;
return false;
}
return true;
}
void XPCMessageServer::ForwardMessage(IPCMessage request,
mach_port_t destination) {
xpc_pipe_t pipe = xpc_pipe_create_from_port(destination, 0);
int rv = xpc_pipe_routine_forward(pipe, request.xpc);
if (rv) {
LOG(ERROR) << "Failed to xpc_pipe_routine_forward(): " << rv;
}
xpc_release(pipe);
}
void XPCMessageServer::RejectMessage(IPCMessage request, int error_code) {
IPCMessage reply = CreateReply(request);
// The message wasn't expecting a reply, so rejecting means ignoring it.
if (reply.xpc) {
xpc_dictionary_set_int64(reply.xpc, "error", error_code);
SendReply(reply);
}
}
mach_port_t XPCMessageServer::GetServerPort() const {
return server_port_.get();
}
void XPCMessageServer::ReceiveMessage() {
IPCMessage request;
int rv = xpc_pipe_receive(server_port_.get(), &request.xpc);
if (rv) {
LOG(ERROR) << "Failed to xpc_pipe_receive(): " << rv;
return;
}
demuxer_->DemuxMessage(request);
xpc_release(request.xpc);
if (reply_message_) {
xpc_release(reply_message_);
reply_message_ = NULL;
}
}
} // namespace sandbox