summaryrefslogtreecommitdiff
path: root/sandbox.c
blob: 9e06155af19eaa347ae0ef9c427704f0606b7bb0 (plain) (blame)
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
152
153
154
155
156
157
158
159
160
161
#include "xs.h"

#include "snac.h"

#if defined(__OpenBSD__)

void sbox_enter(const char *basedir)
{
    const char *address = xs_dict_get(srv_config, "address");

    if (xs_is_true(xs_dict_get(srv_config, "disable_openbsd_security"))) {
        srv_log(xs_dup("OpenBSD security disabled by admin"));
        return;
    }

    int smail = !xs_is_true(xs_dict_get(srv_config, "disable_email_notifications"));

    srv_debug(1, xs_fmt("Calling unveil()"));
    unveil(basedir,                "rwc");
    unveil("/tmp",                 "rwc");
    unveil("/etc/resolv.conf",     "r");
    unveil("/etc/hosts",           "r");
    unveil("/etc/ssl/openssl.cnf", "r");
    unveil("/etc/ssl/cert.pem",    "r");
    unveil("/usr/share/zoneinfo",  "r");

    if (*address == '/')
        unveil(address, "rwc");

    if (smail)
        unveil("/usr/sbin/sendmail",   "x");

    unveil(NULL,                   NULL);

    srv_debug(1, xs_fmt("Calling pledge()"));

    xs *p = xs_str_new("stdio rpath wpath cpath flock inet proc dns fattr");

    if (*address == '/')
        p = xs_str_cat(p, " unix");

    if (smail)
        p = xs_str_cat(p, " exec");

    pledge(p, NULL);
}

#elif defined(__linux__)

#if defined(WITH_LINUX_SANDBOX)

#include <unistd.h>

#define LL_PRINTERR(fmt, ...) srv_debug(0, xs_fmt(fmt, __VA_ARGS__))
#include "landloc.h"

static
LL_BEGIN(sbox_enter_linux_, const char* basedir, const char *address, int smtp_port) {

    const unsigned long long
        rd = LANDLOCK_ACCESS_FS_READ_DIR,
        rf = LANDLOCK_ACCESS_FS_READ_FILE,
        w  = LANDLOCK_ACCESS_FS_WRITE_FILE      |
             LANDLOCK_ACCESS_FS_TRUNCATE_COMPAT,
        c  = LANDLOCK_ACCESS_FS_MAKE_DIR        |
             LANDLOCK_ACCESS_FS_MAKE_REG        |
             LANDLOCK_ACCESS_FS_TRUNCATE_COMPAT |
             LANDLOCK_ACCESS_FS_MAKE_SYM        |
             LANDLOCK_ACCESS_FS_REMOVE_DIR      |
             LANDLOCK_ACCESS_FS_REMOVE_FILE     |
             LANDLOCK_ACCESS_FS_REFER_COMPAT,
        s  = LANDLOCK_ACCESS_FS_MAKE_SOCK,
        x  = LANDLOCK_ACCESS_FS_EXECUTE;
    char *resolved_path = NULL;

    LL_PATH(basedir,                rf|rd|w|c);
    LL_PATH("/tmp",                 rf|rd|w|c);
#ifndef WITHOUT_SHM
    LL_PATH("/dev/shm",             rf|w|c   );
#endif
    LL_PATH("/dev/urandom",         rf       );
    LL_PATH("/etc/resolv.conf",     rf       );
    LL_PATH("/etc/hosts",           rf       );
    LL_PATH("/etc/ssl",             rf|rd    );
    if ((resolved_path = realpath("/etc/ssl/cert.pem", NULL))) {
        /* some distros like cert.pem to be a symlink */
        LL_PATH(resolved_path,      rf       );
        free(resolved_path);
    }
    LL_PATH("/usr/share/zoneinfo",  rf       );

    if (mtime("/etc/pki") > 0)
        LL_PATH("/etc/pki",         rf       );

    if (*address == '/') {
        /* the directory holding the socket must be allowed */
        xs *l = xs_split(address, "/");
        l = xs_list_del(l, -1);
        xs *sdir = xs_join(l, "/");

        LL_PATH(sdir, s);
    }

    if (*address != '/') {
        unsigned short listen_port = xs_number_get(xs_dict_get(srv_config, "port"));
        LL_PORT(listen_port, LANDLOCK_ACCESS_NET_BIND_TCP_COMPAT);
    }

    LL_PORT(80,  LANDLOCK_ACCESS_NET_CONNECT_TCP_COMPAT);
    LL_PORT(443, LANDLOCK_ACCESS_NET_CONNECT_TCP_COMPAT);
    if (smtp_port > 0)
        LL_PORT((unsigned short)smtp_port, LANDLOCK_ACCESS_NET_CONNECT_TCP_COMPAT);

} LL_END

void sbox_enter(const char *basedir)
{
    const char *errstr;
    const char *address = xs_dict_get(srv_config, "address");
    const char *smtp_url = xs_dict_get(srv_config, "smtp_url");
    int smtp_port = -1;

    if (xs_is_true(xs_dict_get(srv_config, "disable_sandbox"))) {
        srv_debug(1, xs_dup("Linux sandbox disabled by admin"));
        return;
    }

    if (xs_is_string(smtp_url) && *smtp_url != '\0') {
        smtp_port = parse_port(smtp_url, &errstr);
        if (errstr)
            srv_debug(0, xs_fmt("Couldn't determine port from '%s': %s", smtp_url, errstr));
    }

    if (sbox_enter_linux_(basedir, address, smtp_port) == 0)
        srv_debug(1, xs_dup("Linux sandbox enabled"));
    else
        srv_debug(0, xs_dup("Linux sandbox failed"));
}

#else /* defined(WITH_LINUX_SANDBOX) */

void sbox_enter(const char *basedir)
{
    (void)basedir;

    srv_debug(1, xs_fmt("Linux sandbox not compiled in"));
}

#endif

#else

/* other OSs: dummy sbox_enter() */

void sbox_enter(const char *basedir)
{
    (void)basedir;
}


#endif /* __OpenBSD__ */