1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "sandbox/mac/xpc_message_server.h"
6
7#include <bsm/libbsm.h>
8
9#include <string>
10
11#include "base/mac/mach_logging.h"
12#include "base/strings/stringprintf.h"
13#include "sandbox/mac/dispatch_source_mach.h"
14#include "sandbox/mac/xpc.h"
15
16namespace sandbox {
17
18XPCMessageServer::XPCMessageServer(MessageDemuxer* demuxer,
19                                   mach_port_t server_receive_right)
20    : demuxer_(demuxer),
21      server_port_(server_receive_right),
22      reply_message_(NULL) {
23}
24
25XPCMessageServer::~XPCMessageServer() {
26}
27
28bool XPCMessageServer::Initialize() {
29  // Allocate a port for use as a new server port if one was not passed to the
30  // constructor.
31  if (!server_port_.is_valid()) {
32    mach_port_t port;
33    kern_return_t kr;
34    if ((kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE,
35            &port)) != KERN_SUCCESS) {
36      MACH_LOG(ERROR, kr) << "Failed to allocate new server port.";
37      return false;
38    }
39    server_port_.reset(port);
40  }
41
42  std::string label = base::StringPrintf(
43      "org.chromium.sandbox.XPCMessageServer.%p", demuxer_);
44  dispatch_source_.reset(new DispatchSourceMach(
45      label.c_str(), server_port_.get(), ^{ ReceiveMessage(); }));
46  dispatch_source_->Resume();
47
48  return true;
49}
50
51pid_t XPCMessageServer::GetMessageSenderPID(IPCMessage request) {
52  audit_token_t token;
53  xpc_dictionary_get_audit_token(request.xpc, &token);
54  // TODO(rsesek): In the 10.7 SDK, there's audit_token_to_pid().
55  pid_t sender_pid;
56  audit_token_to_au32(token,
57      NULL, NULL, NULL, NULL, NULL, &sender_pid, NULL, NULL);
58  return sender_pid;
59}
60
61IPCMessage XPCMessageServer::CreateReply(IPCMessage request) {
62  if (!reply_message_)
63    reply_message_ = xpc_dictionary_create_reply(request.xpc);
64
65  IPCMessage reply;
66  reply.xpc = reply_message_;
67  return reply;
68}
69
70bool XPCMessageServer::SendReply(IPCMessage reply) {
71  int rv = xpc_pipe_routine_reply(reply.xpc);
72  if (rv) {
73    LOG(ERROR) << "Failed to xpc_pipe_routine_reply(): " << rv;
74    return false;
75  }
76  return true;
77}
78
79void XPCMessageServer::ForwardMessage(IPCMessage request,
80                                      mach_port_t destination) {
81  xpc_pipe_t pipe = xpc_pipe_create_from_port(destination, 0);
82  int rv = xpc_pipe_routine_forward(pipe, request.xpc);
83  if (rv) {
84    LOG(ERROR) << "Failed to xpc_pipe_routine_forward(): " << rv;
85  }
86  xpc_release(pipe);
87}
88
89void XPCMessageServer::RejectMessage(IPCMessage request, int error_code) {
90  IPCMessage reply = CreateReply(request);
91  xpc_dictionary_set_int64(reply.xpc, "error", error_code);
92  SendReply(reply);
93}
94
95mach_port_t XPCMessageServer::GetServerPort() const {
96  return server_port_.get();
97}
98
99void XPCMessageServer::ReceiveMessage() {
100  IPCMessage request;
101  int rv = xpc_pipe_receive(server_port_, &request.xpc);
102  if (rv) {
103    LOG(ERROR) << "Failed to xpc_pipe_receive(): " << rv;
104    return;
105  }
106
107  demuxer_->DemuxMessage(request);
108
109  xpc_release(request.xpc);
110  if (reply_message_) {
111    xpc_release(reply_message_);
112    reply_message_ = NULL;
113  }
114}
115
116}  // namespace sandbox
117