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