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
#ifdef __linux__
47
#include <sys/prctl.h>
48
#endif
49
50
static gid_t vju_mgt_gid;
51
static uid_t vju_uid;
52
static gid_t vju_gid;
53
static const char *vju_user;
54
55
static uid_t vju_wrkuid;
56
static gid_t vju_wrkgid;
57
static const char *vju_wrkuser;
58
59
static gid_t vju_cc_gid;
60
static int vju_cc_gid_set;
61
62
#ifndef VARNISH_USER
63
#define VARNISH_USER "varnish"
64
#endif
65
66
#ifndef VCACHE_USER
67
#define VCACHE_USER "vcache"
68
#endif
69
70
#ifndef NGID
71
#define NGID 2000
72
#endif
73
74
static int
75 400
vju_getuid(const char *arg)
76
{
77
        struct passwd *pw;
78
79 400
        pw = getpwnam(arg);
80 400
        if (pw != NULL) {
81 375
                vju_user = strdup(arg);
82 375
                AN(vju_user);
83 375
                vju_uid = pw->pw_uid;
84 375
                vju_gid = pw->pw_gid;
85 375
        }
86 400
        endpwent();
87 400
        return (pw == NULL ? -1 : 0);
88
}
89
90
static int
91 400
vju_getwrkuid(const char *arg)
92
{
93
        struct passwd *pw;
94
95 400
        pw = getpwnam(arg);
96 400
        if (pw != NULL) {
97 375
                vju_wrkuser = strdup(arg);
98 375
                AN(vju_wrkuser);
99 375
                vju_wrkuid = pw->pw_uid;
100 375
                vju_wrkgid = pw->pw_gid;
101 375
        }
102 400
        endpwent();
103 400
        return (pw == NULL ? -1 : 0);
104
}
105
106
static int
107 125
vju_getccgid(const char *arg)
108
{
109
        struct group *gr;
110
111 125
        gr = getgrnam(arg);
112 125
        if (gr != NULL) {
113 100
                vju_cc_gid_set = 1;
114 100
                vju_cc_gid = gr->gr_gid;
115 100
        }
116 125
        endgrent();
117 125
        return (gr == NULL ? -1 : 0);
118
}
119
120
/**********************************************************************
121
 */
122
123
static int v_matchproto_(jail_init_f)
124 24200
vju_init(char **args)
125
{
126 24200
        if (args == NULL) {
127
                /* Autoconfig */
128 23975
                if (geteuid() != 0)
129 23725
                        return (1);
130 250
                if (vju_getuid(VARNISH_USER))
131 0
                        return (1);
132 250
        } else {
133
134 225
                if (geteuid() != 0)
135 0
                        ARGV_ERR("Unix Jail: Must be root.\n");
136
137 475
                for (;*args != NULL; args++) {
138 350
                        if (!strncmp(*args, "user=", 5)) {
139 125
                                if (vju_getuid((*args) + 5))
140 25
                                        ARGV_ERR(
141
                                            "Unix jail: %s user not found.\n",
142
                                            (*args) + 5);
143 100
                                continue;
144
                        }
145 225
                        if (!strncmp(*args, "workuser=", 9)) {
146 75
                                if (vju_getwrkuid((*args) + 9))
147 25
                                        ARGV_ERR(
148
                                            "Unix jail: %s user not found.\n",
149
                                            (*args) + 9);
150 50
                                continue;
151
                        }
152 150
                        if (!strncmp(*args, "ccgroup=", 8)) {
153 125
                                if (vju_getccgid((*args) + 8))
154 25
                                        ARGV_ERR(
155
                                            "Unix jail: %s group not found.\n",
156
                                            (*args) + 8);
157 100
                                continue;
158
                        }
159 25
                        ARGV_ERR("Unix jail: unknown sub-argument '%s'\n",
160
                            *args);
161 0
                }
162
163 125
                if (vju_user == NULL && vju_getuid(VARNISH_USER))
164 0
                        ARGV_ERR("Unix jail: %s user not found.\n",
165
                            VARNISH_USER);
166
        }
167
168 375
        AN(vju_user);
169
170 375
        vju_mgt_gid = getgid();
171
172 375
        if (vju_wrkuser == NULL && vju_getwrkuid(VCACHE_USER)) {
173 0
                vju_wrkuid = vju_uid;
174 0
                vju_wrkgid = vju_gid;
175 0
        }
176
177 375
        if (vju_wrkuser != NULL && vju_wrkgid != vju_gid)
178 25
                ARGV_ERR("Unix jail: user %s and %s have "
179
                    "different login groups\n", vju_user, vju_wrkuser);
180
181
        /* Do an explicit JAIL_MASTER_LOW */
182 350
        AZ(setegid(vju_gid));
183 350
        AZ(seteuid(vju_uid));
184 350
        return (0);
185 24075
}
186
187
static void v_matchproto_(jail_master_f)
188 17325
vju_master(enum jail_master_e jme)
189
{
190 17325
        ASSERT_JAIL_MASTER(jme);
191 17325
        if (jme == JAIL_MASTER_LOW) {
192 8275
                AZ(setegid(vju_gid));
193 8275
                AZ(seteuid(vju_uid));
194 8275
        } else {
195 9050
                AZ(seteuid(0));
196 9050
                AZ(setegid(vju_mgt_gid));
197
        }
198 17325
}
199
200
static void v_matchproto_(jail_subproc_f)
201 700
vju_subproc(enum jail_subproc_e jse)
202
{
203
        int i;
204
        gid_t gid_list[NGID];
205
206 700
        ASSERT_JAIL_SUBPROC(jse);
207 700
        AZ(seteuid(0));
208 1400
        if (vju_wrkuser != NULL &&
209 700
            (jse == JAIL_SUBPROC_VCLLOAD || jse == JAIL_SUBPROC_WORKER)) {
210 0
                AZ(setgid(vju_wrkgid));
211 0
                AZ(initgroups(vju_wrkuser, vju_wrkgid));
212 0
        } else {
213 700
                AZ(setgid(vju_gid));
214 700
                AZ(initgroups(vju_user, vju_gid));
215
        }
216
217 700
        if (jse == JAIL_SUBPROC_CC && vju_cc_gid_set) {
218
                /* Add the optional extra group for the C-compiler access */
219 100
                i = getgroups(NGID, gid_list);
220 100
                assert(i >= 0);
221 100
                gid_list[i++] = vju_cc_gid;
222 100
                AZ(setgroups(i, gid_list));
223 100
        }
224
225 1400
        if (vju_wrkuser != NULL &&
226 700
            (jse == JAIL_SUBPROC_VCLLOAD || jse == JAIL_SUBPROC_WORKER)) {
227 0
                AZ(setuid(vju_wrkuid));
228 0
        } else {
229 700
                AZ(setuid(vju_uid));
230
        }
231
232
#ifdef __linux__
233
        /*
234
         * On linux mucking about with uid/gid disables core-dumps,
235
         * reenable them again.
236
         */
237
        if (prctl(PR_SET_DUMPABLE, 1) != 0) {
238
                MGT_Complain(C_INFO,
239
                    "Could not set dumpable bit.  Core dumps turned off");
240
        }
241
#endif
242 700
}
243
244
static int v_matchproto_(jail_make_dir_f)
245 700
vju_make_subdir(const char *dname, const char *what, struct vsb *vsb)
246
{
247
        int e;
248
249 700
        AN(dname);
250 700
        AN(what);
251 700
        AZ(seteuid(0));
252
253 700
        if (mkdir(dname, 0755) < 0 && errno != EEXIST) {
254 0
                e = errno;
255 0
                if (vsb != NULL) {
256 0
                        VSB_printf(vsb,
257
                            "Cannot create %s directory '%s': %s\n",
258 0
                            what, dname, VAS_errtxt(e));
259 0
                } else {
260 0
                        MGT_Complain(C_ERR,
261
                            "Cannot create %s directory '%s': %s",
262 0
                            what, dname, VAS_errtxt(e));
263
                }
264 0
                return (1);
265
        }
266 700
        AZ(chown(dname, vju_uid, vju_gid));
267 700
        AZ(seteuid(vju_uid));
268 700
        return (0);
269 700
}
270
271
static int v_matchproto_(jail_make_dir_f)
272 350
vju_make_workdir(const char *dname, const char *what, struct vsb *vsb)
273
{
274
275 350
        AN(dname);
276 350
        AZ(what);
277 350
        AZ(vsb);
278 350
        AZ(seteuid(0));
279
280 350
        if (mkdir(dname, 0755) < 0 && errno != EEXIST) {
281 0
                MGT_Complain(C_ERR, "Cannot create working directory '%s': %s",
282 0
                    dname, VAS_errtxt(errno));
283 0
                return (1);
284
        }
285
        //lint -e{570}
286 350
        AZ(chown(dname, -1, vju_gid));
287 350
        AZ(seteuid(vju_uid));
288 350
        return (0);
289 350
}
290
291
static void v_matchproto_(jail_fixfd_f)
292 775
vju_fixfd(int fd, enum jail_fixfd_e what)
293
{
294
        /* Called under JAIL_MASTER_FILE */
295
296 775
        switch (what) {
297
        case JAIL_FIXFD_FILE:
298 0
                AZ(fchmod(fd, 0750));
299 0
                AZ(fchown(fd, vju_wrkuid, vju_wrkgid));
300 0
                break;
301
        case JAIL_FIXFD_VSMMGT:
302 350
                AZ(fchmod(fd, 0750));
303 350
                AZ(fchown(fd, vju_uid, vju_gid));
304 350
                break;
305
        case JAIL_FIXFD_VSMWRK:
306 425
                AZ(fchmod(fd, 0750));
307 425
                AZ(fchown(fd, vju_wrkuid, vju_wrkgid));
308 425
                break;
309
        default:
310 0
                WRONG("Ain't Fixin'");
311 0
        }
312 775
}
313
314
const struct jail_tech jail_tech_unix = {
315
        .magic =        JAIL_TECH_MAGIC,
316
        .name =         "unix",
317
        .init =         vju_init,
318
        .master =       vju_master,
319
        .make_subdir =  vju_make_subdir,
320
        .make_workdir = vju_make_workdir,
321
        .fixfd =        vju_fixfd,
322
        .subproc =      vju_subproc,
323
};