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