Extract filesystem-related functions into fs.c
[tinc] / src / bsd / openbsd / tincd.c
1 #include "../../system.h"
2
3 #include <libgen.h>
4 #include <assert.h>
5
6 #include "sandbox.h"
7 #include "../../device.h"
8 #include "../../logger.h"
9 #include "../../names.h"
10 #include "../../net.h"
11 #include "../../sandbox.h"
12 #include "../../script.h"
13 #include "../../xalloc.h"
14 #include "../../proxy.h"
15
16 static sandbox_level_t current_level = SANDBOX_NONE;
17 static bool can_use_new_paths = true;
18 static bool entered = false;
19
20 static bool chrooted(void) {
21         return !(confbase && *confbase);
22 }
23
24 static void open_conf_subdir(const char *name, const char *privs) {
25         char path[PATH_MAX];
26         snprintf(path, sizeof(path), "%s/%s", confbase, name);
27         allow_path(path, privs);
28 }
29
30 static void open_common_paths(bool can_exec) {
31         // Dummy device uses a fake path, skip it
32         const char *dev = strcasecmp(device, DEVICE_DUMMY) ? device : NULL;
33
34         const unveil_path_t paths[] = {
35                 {"/dev/random",  "r"},
36                 {"/dev/urandom", "r"},
37                 {confbase,       can_exec ? "rx" : "r"},
38                 {dev,            "rw"},
39                 {logfilename,    "rwc"},
40                 {pidfilename,    "rwc"},
41                 {unixsocketname, "rwc"},
42                 {NULL,           NULL},
43         };
44         allow_paths(paths);
45
46         open_conf_subdir("cache", "rwc");
47         open_conf_subdir("hosts", can_exec ? "rwxc" : "rwc");
48         open_conf_subdir("invitations", "rwc");
49 }
50
51 static void open_exec_paths(void) {
52         // proxyhost was checked previously. If we're here, proxyhost
53         // contains the path to the executable, and nothing else.
54         const char *proxy_exec = proxytype == PROXY_EXEC ? proxyhost : NULL;
55
56         const unveil_path_t bin_paths[] = {
57                 {"/bin",            "rx"},
58                 {"/sbin",           "rx"},
59                 {"/usr/bin",        "rx"},
60                 {"/usr/sbin",       "rx"},
61                 {"/usr/local/bin",  "rx"},
62                 {"/usr/local/sbin", "rx"},
63                 {scriptinterpreter, "rx"},
64                 {proxy_exec,        "rx"},
65                 {NULL,              NULL},
66         };
67         allow_paths(bin_paths);
68 }
69
70 static bool sandbox_privs(bool can_exec) {
71         // no mcast since multicasting should be set up by now
72         char promises[512] =
73                 "stdio"  // General I/O, both disk and network
74                 " rpath" // Read files and directories
75                 " wpath" // Write files and directories
76                 " cpath" // Create new ones
77                 " dns"   // Resolve domain names
78                 " inet"  // Make network connections
79                 " unix"; // Control socket connections from tinc CLI
80
81         if(can_exec) {
82                 // fork() and execve() for scripts and exec proxies
83                 const char *exec = " proc exec";
84                 size_t n = strlcat(promises, exec, sizeof(promises));
85                 assert(n < sizeof(promises));
86         }
87
88         return restrict_privs(promises, can_exec ? PROMISES_ALL : PROMISES_NONE);
89 }
90
91 static void sandbox_paths(bool can_exec) {
92         if(chrooted()) {
93                 logger(DEBUG_ALWAYS, LOG_DEBUG, "chroot is used. Disabling path sandbox.");
94                 return;
95         }
96
97         open_common_paths(can_exec);
98         can_use_new_paths = false;
99
100         if(can_exec) {
101                 if(proxytype == PROXY_EXEC && !access(proxyhost, X_OK)) {
102                         logger(DEBUG_ALWAYS, LOG_WARNING, "Looks like a shell expression was used for exec proxy. Using weak path sandbox.");
103                         allow_path("/", "rx");
104                 } else {
105                         open_exec_paths();
106                 }
107         }
108 }
109
110 static bool sandbox_can_after_enter(sandbox_action_t action) {
111         switch(action) {
112         case START_PROCESSES:
113                 return current_level < SANDBOX_HIGH;
114
115         case USE_NEW_PATHS:
116                 return can_use_new_paths;
117
118         default:
119                 abort();
120         }
121 }
122
123 bool sandbox_can(sandbox_action_t action, sandbox_time_t when) {
124         if(when == AFTER_SANDBOX || entered) {
125                 return sandbox_can_after_enter(action);
126         } else {
127                 return true;
128         }
129 }
130
131 void sandbox_set_level(sandbox_level_t level) {
132         assert(!entered);
133         current_level = level;
134 }
135
136 bool sandbox_enter() {
137         assert(!entered);
138         entered = true;
139
140         if(current_level == SANDBOX_NONE) {
141                 logger(DEBUG_ALWAYS, LOG_DEBUG, "Sandbox is disabled");
142                 return true;
143         }
144
145         bool can_exec = sandbox_can_after_enter(START_PROCESSES);
146
147         sandbox_paths(can_exec);
148
149         if(sandbox_privs(can_exec)) {
150                 logger(DEBUG_ALWAYS, LOG_DEBUG, "Entered sandbox at level %d", current_level);
151                 return true;
152         }
153
154         logger(DEBUG_ALWAYS, LOG_ERR, "Could not enter sandbox. Set a lower level or disable it in tinc.conf");
155         current_level = SANDBOX_NONE;
156
157         return false;
158 }