1261287Sdes/*
2261287Sdes * Copyright (c) 2011 Dag-Erling Smorgrav
3261287Sdes *
4261287Sdes * Permission to use, copy, modify, and distribute this software for any
5261287Sdes * purpose with or without fee is hereby granted, provided that the above
6261287Sdes * copyright notice and this permission notice appear in all copies.
7261287Sdes *
8261287Sdes * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9261287Sdes * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10261287Sdes * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11261287Sdes * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12261287Sdes * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13261287Sdes * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14261287Sdes * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15261287Sdes */
16261287Sdes
17261287Sdes#include "includes.h"
18264377Sdes__RCSID("$FreeBSD$");
19261287Sdes
20261287Sdes#ifdef SANDBOX_CAPSICUM
21261287Sdes
22261287Sdes#include <sys/types.h>
23261287Sdes#include <sys/param.h>
24261287Sdes#include <sys/time.h>
25261287Sdes#include <sys/resource.h>
26280250Srwatson#include <sys/capsicum.h>
27261287Sdes
28261287Sdes#include <errno.h>
29261287Sdes#include <stdarg.h>
30261287Sdes#include <stdio.h>
31261287Sdes#include <stdlib.h>
32261287Sdes#include <string.h>
33261287Sdes#include <unistd.h>
34261287Sdes
35261287Sdes#include "log.h"
36261287Sdes#include "monitor.h"
37261287Sdes#include "ssh-sandbox.h"
38261287Sdes#include "xmalloc.h"
39261287Sdes
40261287Sdes/*
41261287Sdes * Capsicum sandbox that sets zero nfiles, nprocs and filesize rlimits,
42261287Sdes * limits rights on stdout, stdin, stderr, monitor and switches to
43261287Sdes * capability mode.
44261287Sdes */
45261287Sdes
46261287Sdesstruct ssh_sandbox {
47261287Sdes	struct monitor *monitor;
48261287Sdes	pid_t child_pid;
49261287Sdes};
50261287Sdes
51261287Sdesstruct ssh_sandbox *
52261287Sdesssh_sandbox_init(struct monitor *monitor)
53261287Sdes{
54261287Sdes	struct ssh_sandbox *box;
55261287Sdes
56261287Sdes	/*
57261287Sdes	 * Strictly, we don't need to maintain any state here but we need
58261287Sdes	 * to return non-NULL to satisfy the API.
59261287Sdes	 */
60261287Sdes	debug3("%s: preparing capsicum sandbox", __func__);
61261287Sdes	box = xcalloc(1, sizeof(*box));
62261287Sdes	box->monitor = monitor;
63261287Sdes	box->child_pid = 0;
64261287Sdes
65261287Sdes	return box;
66261287Sdes}
67261287Sdes
68261287Sdesvoid
69261287Sdesssh_sandbox_child(struct ssh_sandbox *box)
70261287Sdes{
71261287Sdes	struct rlimit rl_zero;
72261287Sdes	cap_rights_t rights;
73261287Sdes
74261287Sdes	rl_zero.rlim_cur = rl_zero.rlim_max = 0;
75261287Sdes
76261287Sdes	if (setrlimit(RLIMIT_FSIZE, &rl_zero) == -1)
77261287Sdes		fatal("%s: setrlimit(RLIMIT_FSIZE, { 0, 0 }): %s",
78261287Sdes			__func__, strerror(errno));
79261287Sdes#ifndef SANDBOX_SKIP_RLIMIT_NOFILE
80261287Sdes	if (setrlimit(RLIMIT_NOFILE, &rl_zero) == -1)
81261287Sdes		fatal("%s: setrlimit(RLIMIT_NOFILE, { 0, 0 }): %s",
82261287Sdes			__func__, strerror(errno));
83261287Sdes#endif
84261287Sdes	if (setrlimit(RLIMIT_NPROC, &rl_zero) == -1)
85261287Sdes		fatal("%s: setrlimit(RLIMIT_NPROC, { 0, 0 }): %s",
86261287Sdes			__func__, strerror(errno));
87261287Sdes
88261287Sdes	cap_rights_init(&rights);
89261287Sdes
90261287Sdes	if (cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS)
91261287Sdes		fatal("can't limit stdin: %m");
92261287Sdes	if (cap_rights_limit(STDOUT_FILENO, &rights) < 0 && errno != ENOSYS)
93261287Sdes		fatal("can't limit stdout: %m");
94261287Sdes	if (cap_rights_limit(STDERR_FILENO, &rights) < 0 && errno != ENOSYS)
95261287Sdes		fatal("can't limit stderr: %m");
96261287Sdes
97261287Sdes	cap_rights_init(&rights, CAP_READ, CAP_WRITE);
98264377Sdes	if (cap_rights_limit(box->monitor->m_recvfd, &rights) < 0 &&
99262718Sdelphij	    errno != ENOSYS)
100261287Sdes		fatal("%s: failed to limit the network socket", __func__);
101261287Sdes	cap_rights_init(&rights, CAP_WRITE);
102264377Sdes	if (cap_rights_limit(box->monitor->m_log_sendfd, &rights) < 0 &&
103262718Sdelphij	    errno != ENOSYS)
104261287Sdes		fatal("%s: failed to limit the logging socket", __func__);
105261287Sdes	if (cap_enter() < 0 && errno != ENOSYS)
106261287Sdes		fatal("%s: failed to enter capability mode", __func__);
107261287Sdes
108261287Sdes}
109261287Sdes
110261287Sdesvoid
111261287Sdesssh_sandbox_parent_finish(struct ssh_sandbox *box)
112261287Sdes{
113261287Sdes	free(box);
114261287Sdes	debug3("%s: finished", __func__);
115261287Sdes}
116261287Sdes
117261287Sdesvoid
118261287Sdesssh_sandbox_parent_preauth(struct ssh_sandbox *box, pid_t child_pid)
119261287Sdes{
120261287Sdes	box->child_pid = child_pid;
121261287Sdes}
122261287Sdes
123261287Sdes#endif /* SANDBOX_CAPSICUM */
124