varnish-cache/bin/varnishd/mgt/mgt_acceptor.c
1
/*-
2
 * Copyright (c) 2006 Verdens Gang AS
3
 * Copyright (c) 2006-2015 Varnish Software AS
4
 * All rights reserved.
5
 *
6
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
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
 * Acceptor socket management
30
 */
31
32
#include "config.h"
33
34
#include <sys/types.h>
35
#include <sys/socket.h>
36
#include <sys/un.h>
37
#include <sys/stat.h>
38
#include <errno.h>
39
#include <stdio.h>
40
#include <stdlib.h>
41
#include <string.h>
42
#include <unistd.h>
43
#include <pwd.h>
44
#include <grp.h>
45
46
#include "mgt/mgt.h"
47
#include "common/heritage.h"
48
49
#include "vav.h"
50
#include "vcli_serve.h"
51
#include "vsa.h"
52
#include "vss.h"
53
#include "vtcp.h"
54
#include "vus.h"
55
56
struct listen_arg {
57
        unsigned                        magic;
58
#define LISTEN_ARG_MAGIC                0xbb2fc333
59
        VTAILQ_ENTRY(listen_arg)        list;
60
        const char                      *endpoint;
61
        const char                      *name;
62
        VTAILQ_HEAD(,listen_sock)       socks;
63
        const struct transport          *transport;
64
        const struct uds_perms          *perms;
65
};
66
67
struct uds_perms {
68
        unsigned        magic;
69
#define UDS_PERMS_MAGIC 0x84fb5635
70
        mode_t          mode;
71
        uid_t           uid;
72
        gid_t           gid;
73
};
74
75
static VTAILQ_HEAD(,listen_arg) listen_args =
76
    VTAILQ_HEAD_INITIALIZER(listen_args);
77
78
static int
79 2912
mac_opensocket(struct listen_sock *ls)
80
{
81
        int fail;
82
        struct sockaddr_un uds;
83
84 2912
        CHECK_OBJ_NOTNULL(ls, LISTEN_SOCK_MAGIC);
85 2912
        if (ls->sock > 0) {
86 1416
                MCH_Fd_Inherit(ls->sock, NULL);
87 1416
                closefd(&ls->sock);
88
        }
89 2912
        if (!ls->uds)
90 2826
                ls->sock = VTCP_bind(ls->addr, NULL);
91
        else {
92 86
                uds.sun_family = PF_UNIX;
93 86
                bprintf(uds.sun_path, "%s", ls->endpoint);
94 86
                ls->sock = VUS_bind(&uds, NULL);
95
        }
96 2912
        fail = errno;
97 2912
        if (ls->sock < 0) {
98 2
                AN(fail);
99 2
                return (fail);
100
        }
101 2910
        if (ls->perms != NULL) {
102 8
                CHECK_OBJ(ls->perms, UDS_PERMS_MAGIC);
103 8
                assert(ls->uds);
104 8
                errno = 0;
105 16
                if (ls->perms->mode != 0 &&
106 8
                    chmod(ls->endpoint, ls->perms->mode) != 0)
107 0
                        return errno;
108 8
                if (chown(ls->endpoint, ls->perms->uid, ls->perms->gid) != 0)
109 0
                        return errno;
110
        }
111 2910
        MCH_Fd_Inherit(ls->sock, "sock");
112 2910
        return (0);
113
}
114
115
/*=====================================================================
116
 * Reopen the accept sockets to get rid of listen status.
117
 * returns the highest errno encountered, 0 for success
118
 */
119
120
int
121 1412
MAC_reopen_sockets(void)
122
{
123
        struct listen_sock *ls;
124 1412
        int err, fail = 0;
125
126 2828
        VTAILQ_FOREACH(ls, &heritage.socks, list) {
127 1416
                VJ_master(JAIL_MASTER_PRIVPORT);
128 1416
                err = mac_opensocket(ls);
129 1416
                VJ_master(JAIL_MASTER_LOW);
130 1416
                if (err == 0)
131 1416
                        continue;
132 0
                if (err > fail)
133 0
                        fail = err;
134 0
                MGT_Complain(C_ERR,
135
                    "Could not reopen listen socket %s: %s",
136
                    ls->endpoint, strerror(err));
137
        }
138 1412
        return fail;
139
}
140
141
/*--------------------------------------------------------------------*/
142
143
static struct listen_sock *
144 1496
mk_listen_sock(const struct listen_arg *la, const struct suckaddr *sa)
145
{
146
        struct listen_sock *ls;
147
        int fail;
148
149 1496
        ALLOC_OBJ(ls, LISTEN_SOCK_MAGIC);
150 1496
        AN(ls);
151 1496
        ls->sock = -1;
152 1496
        ls->addr = VSA_Clone(sa);
153 1496
        AN(ls->addr);
154 1496
        ls->endpoint = strdup(la->endpoint);
155 1496
        AN(ls->endpoint);
156 1496
        ls->name = la->name;
157 1496
        ls->transport = la->transport;
158 1496
        ls->perms = la->perms;
159 1496
        if (*la->endpoint == '/')
160 44
                ls->uds = 1;
161 1496
        VJ_master(JAIL_MASTER_PRIVPORT);
162 1496
        fail = mac_opensocket(ls);
163 1496
        VJ_master(JAIL_MASTER_LOW);
164 1496
        if (fail) {
165 2
                free(ls->addr);
166 2
                free(ls->endpoint);
167 2
                FREE_OBJ(ls);
168 2
                if (fail != EAFNOSUPPORT)
169 2
                        ARGV_ERR("Could not get socket %s: %s\n",
170
                            la->endpoint, strerror(fail));
171 0
                return(NULL);
172
        }
173 1494
        return(ls);
174
}
175
176
static int v_matchproto_(vss_resolved_f)
177 1454
mac_tcp(void *priv, const struct suckaddr *sa)
178
{
179
        struct listen_arg *la;
180
        struct listen_sock *ls;
181
        char abuf[VTCP_ADDRBUFSIZE], pbuf[VTCP_PORTBUFSIZE];
182
        char nbuf[VTCP_ADDRBUFSIZE+VTCP_PORTBUFSIZE+2];
183
184 1454
        CAST_OBJ_NOTNULL(la, priv, LISTEN_ARG_MAGIC);
185
186 1486
        VTAILQ_FOREACH(ls, &heritage.socks, list) {
187 34
                if (!ls->uds && !VSA_Compare(sa, ls->addr))
188 2
                        ARGV_ERR("-a arguments %s and %s have same address\n",
189
                            ls->endpoint, la->endpoint);
190
        }
191 1452
        ls = mk_listen_sock(la, sa);
192 1450
        if (ls == NULL)
193 0
                return(0);
194 1450
        AZ(ls->uds);
195 1450
        if (VSA_Port(ls->addr) == 0) {
196
                /*
197
                 * If the argv port number is zero, we adopt whatever
198
                 * port number this VTCP_bind() found us, as if
199
                 * it was specified by the argv.
200
                 */
201 1448
                free(ls->addr);
202 1448
                ls->addr = VTCP_my_suckaddr(ls->sock);
203 1448
                VTCP_myname(ls->sock, abuf, sizeof abuf,
204
                    pbuf, sizeof pbuf);
205 1448
                bprintf(nbuf, "%s:%s", abuf, pbuf);
206 1448
                REPLACE(ls->endpoint, nbuf);
207
        }
208 1450
        VTAILQ_INSERT_TAIL(&la->socks, ls, arglist);
209 1450
        VTAILQ_INSERT_TAIL(&heritage.socks, ls, list);
210 1450
        return (0);
211
}
212
213
static int v_matchproto_(vus_resolved_f)
214 46
mac_uds(void *priv, const struct sockaddr_un *uds)
215
{
216
        struct listen_arg *la;
217
        struct listen_sock *ls;
218
219 46
        CAST_OBJ_NOTNULL(la, priv, LISTEN_ARG_MAGIC);
220
221 48
        VTAILQ_FOREACH(ls, &heritage.socks, list) {
222 4
                if (ls->uds && strcmp(uds->sun_path, ls->endpoint) == 0)
223 2
                        ARGV_ERR("-a arguments %s and %s have same address\n",
224
                            ls->endpoint, la->endpoint);
225
        }
226 44
        ls = mk_listen_sock(la, bogo_ip);
227 44
        if (ls == NULL)
228 0
                return(0);
229 44
        AN(ls->uds);
230 44
        VTAILQ_INSERT_TAIL(&la->socks, ls, arglist);
231 44
        VTAILQ_INSERT_TAIL(&heritage.socks, ls, list);
232 44
        return (0);
233
}
234
235
void
236 1516
MAC_Arg(const char *spec)
237
{
238
        char **av;
239
        struct listen_arg *la;
240
        const char *err;
241
        int error;
242 1516
        const struct transport *xp = NULL;
243
        const char *name;
244
        char name_buf[8];
245
        static unsigned seq = 0;
246 1516
        struct passwd *pwd = NULL;
247 1516
        struct group *grp = NULL;
248 1516
        mode_t mode = 0;
249
        struct uds_perms *perms;
250
251 1516
        av = MGT_NamedArg(spec, &name, "-a");
252 1516
        AN(av);
253
254 1516
        ALLOC_OBJ(la, LISTEN_ARG_MAGIC);
255 1516
        AN(la);
256 1516
        VTAILQ_INIT(&la->socks);
257 1516
        VTAILQ_INSERT_TAIL(&listen_args, la, list);
258 1516
        la->endpoint = av[1];
259
260 1516
        if (name == NULL) {
261 1506
                bprintf(name_buf, "a%u", seq++);
262 1506
                name = strdup(name_buf);
263 1506
                AN(name);
264
        }
265 1516
        la->name = name;
266
267 1516
        if (*la->endpoint != '/' && strchr(la->endpoint, '/') != NULL)
268 2
                ARGV_ERR("Unix domain socket addresses must be"
269
                    " absolute paths in -a (%s)\n", la->endpoint);
270
271 1514
        if (*la->endpoint == '/' && heritage.min_vcl < 41)
272 76
                heritage.min_vcl = 41;
273
274 1548
        for (int i = 2; av[i] != NULL; i++) {
275
                char *eq, *val;
276
                int len;
277
278 78
                if ((eq = strchr(av[i], '=')) == NULL) {
279 32
                        if (xp != NULL)
280 4
                                ARGV_ERR("Too many protocol sub-args"
281
                                    " in -a (%s)\n", av[i]);
282 28
                        xp = XPORT_Find(av[i]);
283 28
                        if (xp == NULL)
284 4
                                ARGV_ERR("Unknown protocol '%s'\n", av[i]);
285 24
                        continue;
286
                }
287 46
                if (la->endpoint[0] != '/')
288 6
                        ARGV_ERR("Invalid sub-arg %s for IP addresses"
289
                            " in -a\n", av[i]);
290
291 40
                val = eq + 1;
292 40
                len = eq - av[i];
293 40
                assert(len >= 0);
294 40
                if (len == 0)
295 2
                        ARGV_ERR("Invalid sub-arg %s in -a\n", av[i]);
296
297 38
                if (strncmp(av[i], "user", len) == 0) {
298 2
                        if (pwd != NULL)
299 0
                                ARGV_ERR("Too many user sub-args in -a (%s)\n",
300
                                         av[i]);
301 2
                        pwd = getpwnam(val);
302 2
                        if (pwd == NULL)
303 0
                                ARGV_ERR("Unknown user %s in -a\n", val);
304 2
                        continue;
305
                }
306
307 36
                if (strncmp(av[i], "group", len) == 0) {
308 2
                        if (grp != NULL)
309 0
                                ARGV_ERR("Too many group sub-args in -a (%s)\n",
310
                                         av[i]);
311 2
                        grp = getgrnam(val);
312 2
                        if (grp == NULL)
313 0
                                ARGV_ERR("Unknown group %s in -a\n", val);
314 2
                        continue;
315
                }
316
317 34
                if (strncmp(av[i], "mode", len) == 0) {
318
                        long m;
319
                        char *p;
320
321 26
                        if (mode != 0)
322 2
                                ARGV_ERR("Too many mode sub-args in -a (%s)\n",
323
                                         av[i]);
324 24
                        if (*val == '\0')
325 2
                                ARGV_ERR("Empty mode sub-arg in -a\n");
326 22
                        errno = 0;
327 22
                        m = strtol(val, &p, 8);
328 22
                        if (*p != '\0')
329 6
                                ARGV_ERR("Invalid mode sub-arg %s in -a\n",
330
                                         val);
331 16
                        if (errno)
332 4
                                ARGV_ERR("Cannot parse mode sub-arg %s in -a: "
333
                                         "%s\n", val, strerror(errno));
334 12
                        if (m <= 0 || m > 0777)
335 6
                                ARGV_ERR("Mode sub-arg %s out of range in -a\n",
336
                                         val);
337 6
                        mode = (mode_t) m;
338 6
                        continue;
339
                }
340
341 8
                ARGV_ERR("Invalid sub-arg %s in -a\n", av[i]);
342
        }
343
344 1470
        if (xp == NULL)
345 1450
                xp = XPORT_Find("http");
346 1470
        AN(xp);
347 1470
        la->transport = xp;
348
349 1470
        if (pwd != NULL || grp != NULL || mode != 0) {
350 4
                ALLOC_OBJ(perms, UDS_PERMS_MAGIC);
351 4
                AN(perms);
352 4
                if (pwd != NULL)
353 2
                        perms->uid = pwd->pw_uid;
354
                else
355 2
                        perms->uid = (uid_t) -1;
356 4
                if (grp != NULL)
357 2
                        perms->gid = grp->gr_gid;
358
                else
359 2
                        perms->gid = (gid_t) -1;
360 4
                perms->mode = mode;
361 4
                la->perms = perms;
362
        }
363
        else
364 1466
                AZ(la->perms);
365
366 1470
        if (*la->endpoint != '/')
367 1422
                error = VSS_resolver(av[1], "80", mac_tcp, la, &err);
368
        else
369 48
                error = VUS_resolver(av[1], mac_uds, la, &err);
370
371 1464
        if (VTAILQ_EMPTY(&la->socks) || error)
372 2
                ARGV_ERR("Got no socket(s) for %s\n", av[1]);
373 1462
        VAV_Free(av);
374 1462
}