summaryrefslogtreecommitdiff
path: root/main.cc
blob: 5199f2f5297c8c98daa6251c342afaee71586a4e (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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
//
// Copyright (C) 2014 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#include <vector>

#include <base/bind.h>
#include <base/command_line.h>
#include <base/logging.h>
#include <brillo/minijail/minijail.h>
#include <brillo/syslog_logging.h>

#include "apmanager/daemon.h"

using std::vector;

namespace {

namespace switches {

// Don't daemon()ize; run in foreground.
const char kForeground[] = "foreground";
// Flag that causes apmanager to show the help message and exit.
const char kHelp[] = "help";

// The help message shown if help flag is passed to the program.
const char kHelpMessage[] = "\n"
    "Available Switches: \n"
    "  --foreground\n"
    "    Don\'t daemon()ize; run in foreground.\n";
}  // namespace switches

}  // namespace

namespace {

#if !defined(__ANDROID__)
const char kLoggerCommand[] = "/usr/bin/logger";
const char kLoggerUser[] = "syslog";
#endif  // __ANDROID__

const char kSeccompFilePath[] = "/usr/share/policy/apmanager-seccomp.policy";

}  // namespace

// Always logs to the syslog and logs to stderr if
// we are running in the foreground.
void SetupLogging(brillo::Minijail* minijail,
                  bool foreground,
                  const char* daemon_name) {
  int log_flags = 0;
  log_flags |= brillo::kLogToSyslog;
  log_flags |= brillo::kLogHeader;
  if (foreground) {
    log_flags |= brillo::kLogToStderr;
  }
  brillo::InitLog(log_flags);

#if !defined(__ANDROID__)
  // Logger utility doesn't exist on Android, so do not run it on Android.
  // TODO(zqiu): add support to redirect stderr logs from child processes
  // to Android logging facility.
  if (!foreground) {
    vector<char*> logger_command_line;
    int logger_stdin_fd;
    logger_command_line.push_back(const_cast<char*>(kLoggerCommand));
    logger_command_line.push_back(const_cast<char*>("--priority"));
    logger_command_line.push_back(const_cast<char*>("daemon.err"));
    logger_command_line.push_back(const_cast<char*>("--tag"));
    logger_command_line.push_back(const_cast<char*>(daemon_name));
    logger_command_line.push_back(nullptr);

    struct minijail* jail = minijail->New();
    minijail->DropRoot(jail, kLoggerUser, kLoggerUser);

    if (!minijail->RunPipeAndDestroy(jail, logger_command_line,
                                     nullptr, &logger_stdin_fd)) {
      LOG(ERROR) << "Unable to spawn logger. "
                 << "Writes to stderr will be discarded.";
      return;
    }

    // Note that we don't set O_CLOEXEC here. This means that stderr
    // from any child processes will, by default, be logged to syslog.
    if (dup2(logger_stdin_fd, fileno(stderr)) != fileno(stderr)) {
      LOG(ERROR) << "Failed to redirect stderr to syslog: "
                 << strerror(errno);
    }
    close(logger_stdin_fd);
  }
#endif  // __ANDROID__
}

void DropPrivileges(brillo::Minijail* minijail) {
  struct minijail* jail = minijail->New();
  minijail->DropRoot(jail, apmanager::Daemon::kAPManagerUserName,
                     apmanager::Daemon::kAPManagerGroupName);
  // Permissions needed for the daemon and its child processes for managing
  // network interfaces and binding to network sockets.
  minijail->UseCapabilities(jail, CAP_TO_MASK(CAP_NET_ADMIN) |
                                  CAP_TO_MASK(CAP_NET_RAW) |
                                  CAP_TO_MASK(CAP_NET_BIND_SERVICE));
  minijail->UseSeccompFilter(jail, kSeccompFilePath);
  minijail_enter(jail);
  minijail->Destroy(jail);
}

void OnStartup(const char* daemon_name, base::CommandLine* cl) {
  brillo::Minijail* minijail = brillo::Minijail::GetInstance();
  SetupLogging(minijail, cl->HasSwitch(switches::kForeground), daemon_name);

  LOG(INFO) << __func__ << ": Dropping privileges";

  // TODO(zqiu): apmanager is currently started as the "system" user on Android,
  // so there is no need to drop privileges to the "system" user again.
  // Drop user privileges when we're running apmanager under a different
  // user/group.
#if !defined(__ANDROID__)
  // Now that the daemon has all the resources it needs to run, we can drop
  // privileges further.
  DropPrivileges(minijail);
#endif  // __ANDROID
}

int main(int argc, char* argv[]) {
  base::CommandLine::Init(argc, argv);
  base::CommandLine* cl = base::CommandLine::ForCurrentProcess();

  if (cl->HasSwitch(switches::kHelp)) {
    LOG(INFO) << switches::kHelpMessage;
    return 0;
  }

  apmanager::Daemon daemon(base::Bind(&OnStartup, argv[0], cl));

  daemon.Run();

  return 0;
}