15f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// found in the LICENSE file.
45f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
55f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "sandbox/mac/xpc_message_server.h"
65f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include <bsm/libbsm.h>
85f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
95f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include <string>
105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/mac/mach_logging.h"
125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/strings/stringprintf.h"
135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "sandbox/mac/dispatch_source_mach.h"
145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "sandbox/mac/xpc.h"
155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)namespace sandbox {
175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)XPCMessageServer::XPCMessageServer(MessageDemuxer* demuxer,
195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                   mach_port_t server_receive_right)
205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    : demuxer_(demuxer),
215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      server_port_(server_receive_right),
225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      reply_message_(NULL) {
235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)XPCMessageServer::~XPCMessageServer() {
265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool XPCMessageServer::Initialize() {
295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Allocate a port for use as a new server port if one was not passed to the
305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // constructor.
315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!server_port_.is_valid()) {
325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    mach_port_t port;
335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    kern_return_t kr;
345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if ((kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE,
355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            &port)) != KERN_SUCCESS) {
365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      MACH_LOG(ERROR, kr) << "Failed to allocate new server port.";
375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return false;
385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    server_port_.reset(port);
405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::string label = base::StringPrintf(
435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      "org.chromium.sandbox.XPCMessageServer.%p", demuxer_);
445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  dispatch_source_.reset(new DispatchSourceMach(
455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      label.c_str(), server_port_.get(), ^{ ReceiveMessage(); }));
465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  dispatch_source_->Resume();
475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return true;
495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)pid_t XPCMessageServer::GetMessageSenderPID(IPCMessage request) {
525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  audit_token_t token;
535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  xpc_dictionary_get_audit_token(request.xpc, &token);
545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // TODO(rsesek): In the 10.7 SDK, there's audit_token_to_pid().
555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  pid_t sender_pid;
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  audit_token_to_au32(token,
575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      NULL, NULL, NULL, NULL, NULL, &sender_pid, NULL, NULL);
585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return sender_pid;
595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)IPCMessage XPCMessageServer::CreateReply(IPCMessage request) {
625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!reply_message_)
635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    reply_message_ = xpc_dictionary_create_reply(request.xpc);
645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  IPCMessage reply;
665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  reply.xpc = reply_message_;
675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return reply;
685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool XPCMessageServer::SendReply(IPCMessage reply) {
715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int rv = xpc_pipe_routine_reply(reply.xpc);
725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (rv) {
735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    LOG(ERROR) << "Failed to xpc_pipe_routine_reply(): " << rv;
745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return true;
775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void XPCMessageServer::ForwardMessage(IPCMessage request,
805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                      mach_port_t destination) {
815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  xpc_pipe_t pipe = xpc_pipe_create_from_port(destination, 0);
825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int rv = xpc_pipe_routine_forward(pipe, request.xpc);
835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (rv) {
845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    LOG(ERROR) << "Failed to xpc_pipe_routine_forward(): " << rv;
855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  xpc_release(pipe);
875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void XPCMessageServer::RejectMessage(IPCMessage request, int error_code) {
905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  IPCMessage reply = CreateReply(request);
915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  xpc_dictionary_set_int64(reply.xpc, "error", error_code);
925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  SendReply(reply);
935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)mach_port_t XPCMessageServer::GetServerPort() const {
965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return server_port_.get();
975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void XPCMessageServer::ReceiveMessage() {
1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  IPCMessage request;
1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int rv = xpc_pipe_receive(server_port_, &request.xpc);
1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (rv) {
1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    LOG(ERROR) << "Failed to xpc_pipe_receive(): " << rv;
1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  demuxer_->DemuxMessage(request);
1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  xpc_release(request.xpc);
1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (reply_message_) {
1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    xpc_release(reply_message_);
1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    reply_message_ = NULL;
1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}  // namespace sandbox
117