summaryrefslogtreecommitdiffstats
path: root/sandbox/mac/xpc_message_server.cc
blob: 12c8d56e365bd5ce8d1499cf18f6d2c49e9211d4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// 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/dispatch_source_mach.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 DispatchSourceMach(
      label.c_str(), server_port_.get(), ^{ ReceiveMessage(); }));
  dispatch_source_->Resume();

  return true;
}

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) {
  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);
  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_, &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