varnish-cache/bin/varnishd/mgt/mgt_jail_unix.c
0
/*-
1
 * Copyright (c) 2006-2015 Varnish Software AS
2
 * All rights reserved.
3
 *
4
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
5
 *
6
 * SPDX-License-Identifier: BSD-2-Clause
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 *
29
 * Jailing processes the UNIX way, using setuid(2) etc.
30
 */
31
32
#include "config.h"
33
34
#include <fcntl.h>
35
#include <grp.h>
36
#include <pwd.h>
37
#include <stdio.h>
38
#include <stdlib.h>
39
#include <string.h>
40
#include <unistd.h>
41
#include <sys/stat.h>
42
43
#include "mgt/mgt.h"
44
#include "common/heritage.h"
45
46
static gid_t vju_mgt_gid;
47
static uid_t vju_uid;
48
static gid_t vju_gid;
49
static const char *vju_user;
50
51
static uid_t vju_wrkuid;
52
static gid_t vju_wrkgid;
53
static const char *vju_wrkuser;
54
55
static gid_t vju_cc_gid;
56
static int vju_cc_gid_set;
57
58
#ifndef VARNISH_USER
59
#define VARNISH_USER "varnish"
60
#endif
61
62
#ifndef VCACHE_USER
63
#define VCACHE_USER "vcache"
64
#endif
65
66
#ifndef NGID
67
#define NGID 2000
68
#endif
69
70
static int
71 640
vju_getuid(const char *arg)
72
{
73
        struct passwd *pw;
74
75 640
        pw = getpwnam(arg);
76 640
        if (pw != NULL) {
77 600
                vju_user = strdup(arg);
78 600
                AN(vju_user);
79 600
                vju_uid = pw->pw_uid;
80 600
                vju_gid = pw->pw_gid;
81 600
        }
82 640
        endpwent();
83 640
        return (pw == NULL ? -1 : 0);
84
}
85
86
static int
87 640
vju_getwrkuid(const char *arg)
88
{
89
        struct passwd *pw;
90
91 640
        pw = getpwnam(arg);
92 640
        if (pw != NULL) {
93 600
                vju_wrkuser = strdup(arg);
94 600
                AN(vju_wrkuser);
95 600
                vju_wrkuid = pw->pw_uid;
96 600
                vju_wrkgid = pw->pw_gid;
97 600
        }
98 640
        endpwent();
99 640
        return (pw == NULL ? -1 : 0);
100
}
101
102
static int
103 200
vju_getccgid(const char *arg)
104
{
105
        struct group *gr;
106
107 200
        gr = getgrnam(arg);
108 200
        if (gr != NULL) {
109 160
                vju_cc_gid_set = 1;
110 160
                vju_cc_gid = gr->gr_gid;
111 160
        }
112 200
        endgrent();
113 200
        return (gr == NULL ? -1 : 0);
114
}
115
116
/**********************************************************************
117
 */
118
119
static int v_matchproto_(jail_init_f)
120 39760
vju_init(char **args)
121
{
122 39760
        if (args == NULL) {
123
                /* Autoconfig */
124 39400
                if (geteuid() != 0)
125 39000
                        return (1);
126 400
                if (vju_getuid(VARNISH_USER))
127 0
                        return (1);
128 400
        } else {
129
130 360
                if (geteuid() != 0)
131 0
                        ARGV_ERR("Unix Jail: Must be root.\n");
132
133 760
                for (;*args != NULL; args++) {
134 560
                        const char * const a_user = "user=";
135 560
                        const size_t l_user = strlen(a_user);
136 560
                        if (!strncmp(*args, a_user, l_user)) {
137 200
                                if (vju_getuid((*args) + l_user))
138 40
                                        ARGV_ERR(
139
                                            "Unix jail: %s user not found.\n",
140
                                            (*args) + 5);
141 160
                                continue;
142
                        }
143 360
                        const char * const a_workuser = "workuser=";
144 360
                        const size_t l_workuser = strlen(a_workuser);
145 360
                        if (!strncmp(*args, a_workuser, l_workuser)) {
146 120
                                if (vju_getwrkuid((*args) + l_workuser))
147 40
                                        ARGV_ERR(
148
                                            "Unix jail: %s user not found.\n",
149
                                            (*args) + 9);
150 80
                                continue;
151
                        }
152 240
                        const char * const a_ccgroup = "ccgroup=";
153 240
                        const size_t l_ccgroup = strlen(a_ccgroup);
154 240
                        if (!strncmp(*args, "ccgroup=", l_ccgroup)) {
155 200
                                if (vju_getccgid((*args) + l_ccgroup))
156 40
                                        ARGV_ERR(
157
                                            "Unix jail: %s group not found.\n",
158
                                            (*args) + 8);
159 160
                                continue;
160
                        }
161 40
                        ARGV_ERR("Unix jail: unknown sub-argument '%s'\n",
162
                            *args);
163 0
                }
164
165 200
                if (vju_user == NULL && vju_getuid(VARNISH_USER))
166 0
                        ARGV_ERR("Unix jail: %s user not found.\n",
167
                            VARNISH_USER);
168
        }
169
170 600
        AN(vju_user);
171
172 600
        vju_mgt_gid = getgid();
173
174 600
        if (vju_wrkuser == NULL && vju_getwrkuid(VCACHE_USER)) {
175 0
                vju_wrkuid = vju_uid;
176 0
                vju_wrkgid = vju_gid;
177 0
        }
178
179 600
        if (vju_wrkuser != NULL && vju_wrkgid != vju_gid)
180 40
                ARGV_ERR("Unix jail: user %s and %s have "
181
                    "different login groups\n", vju_user, vju_wrkuser);
182
183
        /* Do an explicit JAIL_MASTER_LOW */
184 560
        AZ(setegid(vju_gid));
185 560
        AZ(seteuid(vju_uid));
186 560
        return (0);
187 39560
}
188
189
static void v_matchproto_(jail_master_f)
190 28840
vju_master(enum jail_master_e jme)
191
{
192 28840
        ASSERT_JAIL_MASTER(jme);
193 28840
        if (jme == JAIL_MASTER_LOW) {
194 13800
                AZ(setegid(vju_gid));
195 13800
                AZ(seteuid(vju_uid));
196 13800
        } else {
197 15040
                AZ(seteuid(0));
198 15040
                AZ(setegid(vju_mgt_gid));
199
        }
200 28840
}
201
202
static void v_matchproto_(jail_subproc_f)
203 1120
vju_subproc(enum jail_subproc_e jse)
204
{
205
        int i;
206
        gid_t gid_list[NGID];
207
208 1120
        ASSERT_JAIL_SUBPROC(jse);
209 1120
        AZ(seteuid(0));
210 2240
        if (vju_wrkuser != NULL &&
211 1120
            (jse == JAIL_SUBPROC_VCLLOAD || jse == JAIL_SUBPROC_WORKER)) {
212 0
                AZ(setgid(vju_wrkgid));
213 0
                AZ(initgroups(vju_wrkuser, vju_wrkgid));
214 0
        } else {
215 1120
                AZ(setgid(vju_gid));
216 1120
                AZ(initgroups(vju_user, vju_gid));
217
        }
218
219 1120
        if (jse == JAIL_SUBPROC_CC && vju_cc_gid_set) {
220
                /* Add the optional extra group for the C-compiler access */
221 160
                i = getgroups(NGID, gid_list);
222 160
                assert(i >= 0);
223 160
                assert(i < NGID - 1);
224 160
                gid_list[i++] = vju_cc_gid;
225 160
                AZ(setgroups(i, gid_list));
226 160
        }
227
228 2240
        if (vju_wrkuser != NULL &&
229 1120
            (jse == JAIL_SUBPROC_VCLLOAD || jse == JAIL_SUBPROC_WORKER)) {
230 0
                AZ(setuid(vju_wrkuid));
231 0
        } else {
232 1120
                AZ(setuid(vju_uid));
233
        }
234 1120
}
235
236
static int v_matchproto_(jail_make_dir_f)
237 1680
vju_make_subdir(const char *dname, const char *what, struct vsb *vsb)
238
{
239
        int e;
240
241 1680
        AN(dname);
242 1680
        AN(what);
243 1680
        AZ(seteuid(0));
244
245 1680
        if (mkdir(dname, 0755) < 0 && errno != EEXIST) {
246 0
                e = errno;
247 0
                if (vsb != NULL) {
248 0
                        VSB_printf(vsb,
249
                            "Cannot create %s directory '%s': %s\n",
250 0
                            what, dname, VAS_errtxt(e));
251 0
                } else {
252 0
                        MGT_Complain(C_ERR,
253
                            "Cannot create %s directory '%s': %s",
254 0
                            what, dname, VAS_errtxt(e));
255
                }
256 0
                return (1);
257
        }
258 1680
        AZ(chown(dname, vju_uid, vju_gid));
259 1680
        AZ(seteuid(vju_uid));
260 1680
        return (0);
261 1680
}
262
263
static int v_matchproto_(jail_make_dir_f)
264 560
vju_make_workdir(const char *dname, const char *what, struct vsb *vsb)
265
{
266
267 560
        AN(dname);
268 560
        AZ(what);
269 560
        AZ(vsb);
270 560
        AZ(seteuid(0));
271
272 560
        if (mkdir(dname, 0755) < 0 && errno != EEXIST) {
273 0
                MGT_Complain(C_ERR, "Cannot create working directory '%s': %s",
274 0
                    dname, VAS_errtxt(errno));
275 0
                return (1);
276
        }
277
        //lint -e{570}
278 560
        AZ(chown(dname, -1, vju_gid));
279 560
        AZ(seteuid(vju_uid));
280 560
        return (0);
281 560
}
282
283
static void v_matchproto_(jail_fixfd_f)
284 1800
vju_fixfd(int fd, enum jail_fixfd_e what)
285
{
286
        /* Called under JAIL_MASTER_FILE */
287
288 1800
        switch (what) {
289
        case JAIL_FIXFD_FILE:
290 0
                AZ(fchmod(fd, 0600));
291 0
                AZ(fchown(fd, vju_wrkuid, vju_wrkgid));
292 0
                break;
293
        case JAIL_FIXFD_VSMMGT:
294 560
                AZ(fchmod(fd, 0750));
295 560
                AZ(fchown(fd, vju_uid, vju_gid));
296 560
                break;
297
        case JAIL_FIXFD_VSMWRK:
298
        case JAIL_FIXFD_WRKTMP:
299 1240
                AZ(fchmod(fd, 0750));
300 1240
                AZ(fchown(fd, vju_wrkuid, vju_wrkgid));
301 1240
                break;
302
        default:
303 0
                WRONG("Ain't Fixin'");
304 0
        }
305 1800
}
306
307
const struct jail_tech jail_tech_unix = {
308
        .magic =        JAIL_TECH_MAGIC,
309
        .name =         "unix",
310
        .init =         vju_init,
311
        .master =       vju_master,
312
        .make_subdir =  vju_make_subdir,
313
        .make_workdir = vju_make_workdir,
314
        .fixfd =        vju_fixfd,
315
        .subproc =      vju_subproc,
316
};