1*5f4c09ddSEd Maste /* $NetBSD: bl.c,v 1.28 2016/07/29 17:13:09 christos Exp $ */
2*5f4c09ddSEd Maste
3*5f4c09ddSEd Maste /*-
4*5f4c09ddSEd Maste * Copyright (c) 2014 The NetBSD Foundation, Inc.
5*5f4c09ddSEd Maste * All rights reserved.
6*5f4c09ddSEd Maste *
7*5f4c09ddSEd Maste * This code is derived from software contributed to The NetBSD Foundation
8*5f4c09ddSEd Maste * by Christos Zoulas.
9*5f4c09ddSEd Maste *
10*5f4c09ddSEd Maste * Redistribution and use in source and binary forms, with or without
11*5f4c09ddSEd Maste * modification, are permitted provided that the following conditions
12*5f4c09ddSEd Maste * are met:
13*5f4c09ddSEd Maste * 1. Redistributions of source code must retain the above copyright
14*5f4c09ddSEd Maste * notice, this list of conditions and the following disclaimer.
15*5f4c09ddSEd Maste * 2. Redistributions in binary form must reproduce the above copyright
16*5f4c09ddSEd Maste * notice, this list of conditions and the following disclaimer in the
17*5f4c09ddSEd Maste * documentation and/or other materials provided with the distribution.
18*5f4c09ddSEd Maste *
19*5f4c09ddSEd Maste * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20*5f4c09ddSEd Maste * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21*5f4c09ddSEd Maste * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22*5f4c09ddSEd Maste * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23*5f4c09ddSEd Maste * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24*5f4c09ddSEd Maste * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25*5f4c09ddSEd Maste * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26*5f4c09ddSEd Maste * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27*5f4c09ddSEd Maste * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28*5f4c09ddSEd Maste * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29*5f4c09ddSEd Maste * POSSIBILITY OF SUCH DAMAGE.
30*5f4c09ddSEd Maste */
31*5f4c09ddSEd Maste #ifdef HAVE_CONFIG_H
32*5f4c09ddSEd Maste #include "config.h"
33*5f4c09ddSEd Maste #endif
34*5f4c09ddSEd Maste
35*5f4c09ddSEd Maste #include <sys/cdefs.h>
36*5f4c09ddSEd Maste __RCSID("$NetBSD: bl.c,v 1.28 2016/07/29 17:13:09 christos Exp $");
37*5f4c09ddSEd Maste
38*5f4c09ddSEd Maste #include <sys/param.h>
39*5f4c09ddSEd Maste #include <sys/types.h>
40*5f4c09ddSEd Maste #include <sys/socket.h>
41*5f4c09ddSEd Maste #include <sys/stat.h>
42*5f4c09ddSEd Maste #include <sys/un.h>
43*5f4c09ddSEd Maste
44*5f4c09ddSEd Maste #include <stdio.h>
45*5f4c09ddSEd Maste #include <string.h>
46*5f4c09ddSEd Maste #include <syslog.h>
47*5f4c09ddSEd Maste #include <signal.h>
48*5f4c09ddSEd Maste #include <fcntl.h>
49*5f4c09ddSEd Maste #include <stdlib.h>
50*5f4c09ddSEd Maste #include <unistd.h>
51*5f4c09ddSEd Maste #include <stdint.h>
52*5f4c09ddSEd Maste #include <stdbool.h>
53*5f4c09ddSEd Maste #include <errno.h>
54*5f4c09ddSEd Maste #include <stdarg.h>
55*5f4c09ddSEd Maste #include <netinet/in.h>
56*5f4c09ddSEd Maste #ifdef _REENTRANT
57*5f4c09ddSEd Maste #include <pthread.h>
58*5f4c09ddSEd Maste #endif
59*5f4c09ddSEd Maste
60*5f4c09ddSEd Maste #include "bl.h"
61*5f4c09ddSEd Maste
62*5f4c09ddSEd Maste typedef struct {
63*5f4c09ddSEd Maste uint32_t bl_len;
64*5f4c09ddSEd Maste uint32_t bl_version;
65*5f4c09ddSEd Maste uint32_t bl_type;
66*5f4c09ddSEd Maste uint32_t bl_salen;
67*5f4c09ddSEd Maste struct sockaddr_storage bl_ss;
68*5f4c09ddSEd Maste char bl_data[];
69*5f4c09ddSEd Maste } bl_message_t;
70*5f4c09ddSEd Maste
71*5f4c09ddSEd Maste struct blacklist {
72*5f4c09ddSEd Maste #ifdef _REENTRANT
73*5f4c09ddSEd Maste pthread_mutex_t b_mutex;
74*5f4c09ddSEd Maste # define BL_INIT(b) pthread_mutex_init(&b->b_mutex, NULL)
75*5f4c09ddSEd Maste # define BL_LOCK(b) pthread_mutex_lock(&b->b_mutex)
76*5f4c09ddSEd Maste # define BL_UNLOCK(b) pthread_mutex_unlock(&b->b_mutex)
77*5f4c09ddSEd Maste #else
78*5f4c09ddSEd Maste # define BL_INIT(b) do {} while(/*CONSTCOND*/0)
79*5f4c09ddSEd Maste # define BL_LOCK(b) BL_INIT(b)
80*5f4c09ddSEd Maste # define BL_UNLOCK(b) BL_INIT(b)
81*5f4c09ddSEd Maste #endif
82*5f4c09ddSEd Maste int b_fd;
83*5f4c09ddSEd Maste int b_connected;
84*5f4c09ddSEd Maste struct sockaddr_un b_sun;
85*5f4c09ddSEd Maste void (*b_fun)(int, const char *, va_list);
86*5f4c09ddSEd Maste bl_info_t b_info;
87*5f4c09ddSEd Maste };
88*5f4c09ddSEd Maste
89*5f4c09ddSEd Maste #define BL_VERSION 1
90*5f4c09ddSEd Maste
91*5f4c09ddSEd Maste bool
bl_isconnected(bl_t b)92*5f4c09ddSEd Maste bl_isconnected(bl_t b)
93*5f4c09ddSEd Maste {
94*5f4c09ddSEd Maste return b->b_connected == 0;
95*5f4c09ddSEd Maste }
96*5f4c09ddSEd Maste
97*5f4c09ddSEd Maste int
bl_getfd(bl_t b)98*5f4c09ddSEd Maste bl_getfd(bl_t b)
99*5f4c09ddSEd Maste {
100*5f4c09ddSEd Maste return b->b_fd;
101*5f4c09ddSEd Maste }
102*5f4c09ddSEd Maste
103*5f4c09ddSEd Maste static void
bl_reset(bl_t b,bool locked)104*5f4c09ddSEd Maste bl_reset(bl_t b, bool locked)
105*5f4c09ddSEd Maste {
106*5f4c09ddSEd Maste int serrno = errno;
107*5f4c09ddSEd Maste if (!locked)
108*5f4c09ddSEd Maste BL_LOCK(b);
109*5f4c09ddSEd Maste close(b->b_fd);
110*5f4c09ddSEd Maste errno = serrno;
111*5f4c09ddSEd Maste b->b_fd = -1;
112*5f4c09ddSEd Maste b->b_connected = -1;
113*5f4c09ddSEd Maste if (!locked)
114*5f4c09ddSEd Maste BL_UNLOCK(b);
115*5f4c09ddSEd Maste }
116*5f4c09ddSEd Maste
117*5f4c09ddSEd Maste static void
bl_log(void (* fun)(int,const char *,va_list),int level,const char * fmt,...)118*5f4c09ddSEd Maste bl_log(void (*fun)(int, const char *, va_list), int level,
119*5f4c09ddSEd Maste const char *fmt, ...)
120*5f4c09ddSEd Maste {
121*5f4c09ddSEd Maste va_list ap;
122*5f4c09ddSEd Maste int serrno = errno;
123*5f4c09ddSEd Maste
124*5f4c09ddSEd Maste va_start(ap, fmt);
125*5f4c09ddSEd Maste (*fun)(level, fmt, ap);
126*5f4c09ddSEd Maste va_end(ap);
127*5f4c09ddSEd Maste errno = serrno;
128*5f4c09ddSEd Maste }
129*5f4c09ddSEd Maste
130*5f4c09ddSEd Maste static int
bl_init(bl_t b,bool srv)131*5f4c09ddSEd Maste bl_init(bl_t b, bool srv)
132*5f4c09ddSEd Maste {
133*5f4c09ddSEd Maste static int one = 1;
134*5f4c09ddSEd Maste /* AF_UNIX address of local logger */
135*5f4c09ddSEd Maste mode_t om;
136*5f4c09ddSEd Maste int rv, serrno;
137*5f4c09ddSEd Maste struct sockaddr_un *sun = &b->b_sun;
138*5f4c09ddSEd Maste
139*5f4c09ddSEd Maste #ifndef SOCK_NONBLOCK
140*5f4c09ddSEd Maste #define SOCK_NONBLOCK 0
141*5f4c09ddSEd Maste #endif
142*5f4c09ddSEd Maste #ifndef SOCK_CLOEXEC
143*5f4c09ddSEd Maste #define SOCK_CLOEXEC 0
144*5f4c09ddSEd Maste #endif
145*5f4c09ddSEd Maste #ifndef SOCK_NOSIGPIPE
146*5f4c09ddSEd Maste #define SOCK_NOSIGPIPE 0
147*5f4c09ddSEd Maste #endif
148*5f4c09ddSEd Maste
149*5f4c09ddSEd Maste BL_LOCK(b);
150*5f4c09ddSEd Maste
151*5f4c09ddSEd Maste if (b->b_fd == -1) {
152*5f4c09ddSEd Maste b->b_fd = socket(PF_LOCAL,
153*5f4c09ddSEd Maste SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK|SOCK_NOSIGPIPE, 0);
154*5f4c09ddSEd Maste if (b->b_fd == -1) {
155*5f4c09ddSEd Maste bl_log(b->b_fun, LOG_ERR, "%s: socket failed (%s)",
156*5f4c09ddSEd Maste __func__, strerror(errno));
157*5f4c09ddSEd Maste BL_UNLOCK(b);
158*5f4c09ddSEd Maste return -1;
159*5f4c09ddSEd Maste }
160*5f4c09ddSEd Maste #if SOCK_CLOEXEC == 0
161*5f4c09ddSEd Maste fcntl(b->b_fd, F_SETFD, FD_CLOEXEC);
162*5f4c09ddSEd Maste #endif
163*5f4c09ddSEd Maste #if SOCK_NONBLOCK == 0
164*5f4c09ddSEd Maste fcntl(b->b_fd, F_SETFL, fcntl(b->b_fd, F_GETFL) | O_NONBLOCK);
165*5f4c09ddSEd Maste #endif
166*5f4c09ddSEd Maste #if SOCK_NOSIGPIPE == 0
167*5f4c09ddSEd Maste #ifdef SO_NOSIGPIPE
168*5f4c09ddSEd Maste int o = 1;
169*5f4c09ddSEd Maste setsockopt(b->b_fd, SOL_SOCKET, SO_NOSIGPIPE, &o, sizeof(o));
170*5f4c09ddSEd Maste #else
171*5f4c09ddSEd Maste signal(SIGPIPE, SIG_IGN);
172*5f4c09ddSEd Maste #endif
173*5f4c09ddSEd Maste #endif
174*5f4c09ddSEd Maste }
175*5f4c09ddSEd Maste
176*5f4c09ddSEd Maste if (bl_isconnected(b)) {
177*5f4c09ddSEd Maste BL_UNLOCK(b);
178*5f4c09ddSEd Maste return 0;
179*5f4c09ddSEd Maste }
180*5f4c09ddSEd Maste
181*5f4c09ddSEd Maste /*
182*5f4c09ddSEd Maste * We try to connect anyway even when we are a server to verify
183*5f4c09ddSEd Maste * that no other server is listening to the socket. If we succeed
184*5f4c09ddSEd Maste * to connect and we are a server, someone else owns it.
185*5f4c09ddSEd Maste */
186*5f4c09ddSEd Maste rv = connect(b->b_fd, (const void *)sun, (socklen_t)sizeof(*sun));
187*5f4c09ddSEd Maste if (rv == 0) {
188*5f4c09ddSEd Maste if (srv) {
189*5f4c09ddSEd Maste bl_log(b->b_fun, LOG_ERR,
190*5f4c09ddSEd Maste "%s: another daemon is handling `%s'",
191*5f4c09ddSEd Maste __func__, sun->sun_path);
192*5f4c09ddSEd Maste goto out;
193*5f4c09ddSEd Maste }
194*5f4c09ddSEd Maste } else {
195*5f4c09ddSEd Maste if (!srv) {
196*5f4c09ddSEd Maste /*
197*5f4c09ddSEd Maste * If the daemon is not running, we just try a
198*5f4c09ddSEd Maste * connect, so leave the socket alone until it does
199*5f4c09ddSEd Maste * and only log once.
200*5f4c09ddSEd Maste */
201*5f4c09ddSEd Maste if (b->b_connected != 1) {
202*5f4c09ddSEd Maste bl_log(b->b_fun, LOG_DEBUG,
203*5f4c09ddSEd Maste "%s: connect failed for `%s' (%s)",
204*5f4c09ddSEd Maste __func__, sun->sun_path, strerror(errno));
205*5f4c09ddSEd Maste b->b_connected = 1;
206*5f4c09ddSEd Maste }
207*5f4c09ddSEd Maste BL_UNLOCK(b);
208*5f4c09ddSEd Maste return -1;
209*5f4c09ddSEd Maste }
210*5f4c09ddSEd Maste bl_log(b->b_fun, LOG_DEBUG, "Connected to blacklist server",
211*5f4c09ddSEd Maste __func__);
212*5f4c09ddSEd Maste }
213*5f4c09ddSEd Maste
214*5f4c09ddSEd Maste if (srv) {
215*5f4c09ddSEd Maste (void)unlink(sun->sun_path);
216*5f4c09ddSEd Maste om = umask(0);
217*5f4c09ddSEd Maste rv = bind(b->b_fd, (const void *)sun, (socklen_t)sizeof(*sun));
218*5f4c09ddSEd Maste serrno = errno;
219*5f4c09ddSEd Maste (void)umask(om);
220*5f4c09ddSEd Maste errno = serrno;
221*5f4c09ddSEd Maste if (rv == -1) {
222*5f4c09ddSEd Maste bl_log(b->b_fun, LOG_ERR,
223*5f4c09ddSEd Maste "%s: bind failed for `%s' (%s)",
224*5f4c09ddSEd Maste __func__, sun->sun_path, strerror(errno));
225*5f4c09ddSEd Maste goto out;
226*5f4c09ddSEd Maste }
227*5f4c09ddSEd Maste }
228*5f4c09ddSEd Maste
229*5f4c09ddSEd Maste b->b_connected = 0;
230*5f4c09ddSEd Maste #define GOT_FD 1
231*5f4c09ddSEd Maste #if defined(LOCAL_CREDS)
232*5f4c09ddSEd Maste #define CRED_LEVEL 0
233*5f4c09ddSEd Maste #define CRED_NAME LOCAL_CREDS
234*5f4c09ddSEd Maste #define CRED_SC_UID sc_euid
235*5f4c09ddSEd Maste #define CRED_SC_GID sc_egid
236*5f4c09ddSEd Maste #define CRED_MESSAGE SCM_CREDS
237*5f4c09ddSEd Maste #define CRED_SIZE SOCKCREDSIZE(NGROUPS_MAX)
238*5f4c09ddSEd Maste #define CRED_TYPE struct sockcred
239*5f4c09ddSEd Maste #define GOT_CRED 2
240*5f4c09ddSEd Maste #elif defined(SO_PASSCRED)
241*5f4c09ddSEd Maste #define CRED_LEVEL SOL_SOCKET
242*5f4c09ddSEd Maste #define CRED_NAME SO_PASSCRED
243*5f4c09ddSEd Maste #define CRED_SC_UID uid
244*5f4c09ddSEd Maste #define CRED_SC_GID gid
245*5f4c09ddSEd Maste #define CRED_MESSAGE SCM_CREDENTIALS
246*5f4c09ddSEd Maste #define CRED_SIZE sizeof(struct ucred)
247*5f4c09ddSEd Maste #define CRED_TYPE struct ucred
248*5f4c09ddSEd Maste #define GOT_CRED 2
249*5f4c09ddSEd Maste #else
250*5f4c09ddSEd Maste #define GOT_CRED 0
251*5f4c09ddSEd Maste /*
252*5f4c09ddSEd Maste * getpeereid() and LOCAL_PEERCRED don't help here
253*5f4c09ddSEd Maste * because we are not a stream socket!
254*5f4c09ddSEd Maste */
255*5f4c09ddSEd Maste #define CRED_SIZE 0
256*5f4c09ddSEd Maste #define CRED_TYPE void * __unused
257*5f4c09ddSEd Maste #endif
258*5f4c09ddSEd Maste
259*5f4c09ddSEd Maste #ifdef CRED_LEVEL
260*5f4c09ddSEd Maste if (setsockopt(b->b_fd, CRED_LEVEL, CRED_NAME,
261*5f4c09ddSEd Maste &one, (socklen_t)sizeof(one)) == -1) {
262*5f4c09ddSEd Maste bl_log(b->b_fun, LOG_ERR, "%s: setsockopt %s "
263*5f4c09ddSEd Maste "failed (%s)", __func__, __STRING(CRED_NAME),
264*5f4c09ddSEd Maste strerror(errno));
265*5f4c09ddSEd Maste goto out;
266*5f4c09ddSEd Maste }
267*5f4c09ddSEd Maste #endif
268*5f4c09ddSEd Maste
269*5f4c09ddSEd Maste BL_UNLOCK(b);
270*5f4c09ddSEd Maste return 0;
271*5f4c09ddSEd Maste out:
272*5f4c09ddSEd Maste bl_reset(b, true);
273*5f4c09ddSEd Maste BL_UNLOCK(b);
274*5f4c09ddSEd Maste return -1;
275*5f4c09ddSEd Maste }
276*5f4c09ddSEd Maste
277*5f4c09ddSEd Maste bl_t
bl_create(bool srv,const char * path,void (* fun)(int,const char *,va_list))278*5f4c09ddSEd Maste bl_create(bool srv, const char *path, void (*fun)(int, const char *, va_list))
279*5f4c09ddSEd Maste {
280*5f4c09ddSEd Maste bl_t b = calloc(1, sizeof(*b));
281*5f4c09ddSEd Maste if (b == NULL)
282*5f4c09ddSEd Maste goto out;
283*5f4c09ddSEd Maste b->b_fun = fun == NULL ? vsyslog : fun;
284*5f4c09ddSEd Maste b->b_fd = -1;
285*5f4c09ddSEd Maste b->b_connected = -1;
286*5f4c09ddSEd Maste BL_INIT(b);
287*5f4c09ddSEd Maste
288*5f4c09ddSEd Maste memset(&b->b_sun, 0, sizeof(b->b_sun));
289*5f4c09ddSEd Maste b->b_sun.sun_family = AF_LOCAL;
290*5f4c09ddSEd Maste #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
291*5f4c09ddSEd Maste b->b_sun.sun_len = sizeof(b->b_sun);
292*5f4c09ddSEd Maste #endif
293*5f4c09ddSEd Maste strlcpy(b->b_sun.sun_path,
294*5f4c09ddSEd Maste path ? path : _PATH_BLSOCK, sizeof(b->b_sun.sun_path));
295*5f4c09ddSEd Maste
296*5f4c09ddSEd Maste bl_init(b, srv);
297*5f4c09ddSEd Maste return b;
298*5f4c09ddSEd Maste out:
299*5f4c09ddSEd Maste free(b);
300*5f4c09ddSEd Maste bl_log(fun, LOG_ERR, "%s: malloc failed (%s)", __func__,
301*5f4c09ddSEd Maste strerror(errno));
302*5f4c09ddSEd Maste return NULL;
303*5f4c09ddSEd Maste }
304*5f4c09ddSEd Maste
305*5f4c09ddSEd Maste void
bl_destroy(bl_t b)306*5f4c09ddSEd Maste bl_destroy(bl_t b)
307*5f4c09ddSEd Maste {
308*5f4c09ddSEd Maste bl_reset(b, false);
309*5f4c09ddSEd Maste free(b);
310*5f4c09ddSEd Maste }
311*5f4c09ddSEd Maste
312*5f4c09ddSEd Maste static int
bl_getsock(bl_t b,struct sockaddr_storage * ss,const struct sockaddr * sa,socklen_t slen,const char * ctx)313*5f4c09ddSEd Maste bl_getsock(bl_t b, struct sockaddr_storage *ss, const struct sockaddr *sa,
314*5f4c09ddSEd Maste socklen_t slen, const char *ctx)
315*5f4c09ddSEd Maste {
316*5f4c09ddSEd Maste uint8_t family;
317*5f4c09ddSEd Maste
318*5f4c09ddSEd Maste memset(ss, 0, sizeof(*ss));
319*5f4c09ddSEd Maste
320*5f4c09ddSEd Maste switch (slen) {
321*5f4c09ddSEd Maste case 0:
322*5f4c09ddSEd Maste return 0;
323*5f4c09ddSEd Maste case sizeof(struct sockaddr_in):
324*5f4c09ddSEd Maste family = AF_INET;
325*5f4c09ddSEd Maste break;
326*5f4c09ddSEd Maste case sizeof(struct sockaddr_in6):
327*5f4c09ddSEd Maste family = AF_INET6;
328*5f4c09ddSEd Maste break;
329*5f4c09ddSEd Maste default:
330*5f4c09ddSEd Maste bl_log(b->b_fun, LOG_ERR, "%s: invalid socket len %u (%s)",
331*5f4c09ddSEd Maste __func__, (unsigned)slen, ctx);
332*5f4c09ddSEd Maste errno = EINVAL;
333*5f4c09ddSEd Maste return -1;
334*5f4c09ddSEd Maste }
335*5f4c09ddSEd Maste
336*5f4c09ddSEd Maste memcpy(ss, sa, slen);
337*5f4c09ddSEd Maste
338*5f4c09ddSEd Maste if (ss->ss_family != family) {
339*5f4c09ddSEd Maste bl_log(b->b_fun, LOG_INFO,
340*5f4c09ddSEd Maste "%s: correcting socket family %d to %d (%s)",
341*5f4c09ddSEd Maste __func__, ss->ss_family, family, ctx);
342*5f4c09ddSEd Maste ss->ss_family = family;
343*5f4c09ddSEd Maste }
344*5f4c09ddSEd Maste
345*5f4c09ddSEd Maste #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
346*5f4c09ddSEd Maste if (ss->ss_len != slen) {
347*5f4c09ddSEd Maste bl_log(b->b_fun, LOG_INFO,
348*5f4c09ddSEd Maste "%s: correcting socket len %u to %u (%s)",
349*5f4c09ddSEd Maste __func__, ss->ss_len, (unsigned)slen, ctx);
350*5f4c09ddSEd Maste ss->ss_len = (uint8_t)slen;
351*5f4c09ddSEd Maste }
352*5f4c09ddSEd Maste #endif
353*5f4c09ddSEd Maste return 0;
354*5f4c09ddSEd Maste }
355*5f4c09ddSEd Maste
356*5f4c09ddSEd Maste int
bl_send(bl_t b,bl_type_t e,int pfd,const struct sockaddr * sa,socklen_t slen,const char * ctx)357*5f4c09ddSEd Maste bl_send(bl_t b, bl_type_t e, int pfd, const struct sockaddr *sa,
358*5f4c09ddSEd Maste socklen_t slen, const char *ctx)
359*5f4c09ddSEd Maste {
360*5f4c09ddSEd Maste struct msghdr msg;
361*5f4c09ddSEd Maste struct iovec iov;
362*5f4c09ddSEd Maste union {
363*5f4c09ddSEd Maste char ctrl[CMSG_SPACE(sizeof(int))];
364*5f4c09ddSEd Maste uint32_t fd;
365*5f4c09ddSEd Maste } ua;
366*5f4c09ddSEd Maste struct cmsghdr *cmsg;
367*5f4c09ddSEd Maste union {
368*5f4c09ddSEd Maste bl_message_t bl;
369*5f4c09ddSEd Maste char buf[512];
370*5f4c09ddSEd Maste } ub;
371*5f4c09ddSEd Maste size_t ctxlen, tried;
372*5f4c09ddSEd Maste #define NTRIES 5
373*5f4c09ddSEd Maste
374*5f4c09ddSEd Maste ctxlen = strlen(ctx);
375*5f4c09ddSEd Maste if (ctxlen > 128)
376*5f4c09ddSEd Maste ctxlen = 128;
377*5f4c09ddSEd Maste
378*5f4c09ddSEd Maste iov.iov_base = ub.buf;
379*5f4c09ddSEd Maste iov.iov_len = sizeof(bl_message_t) + ctxlen;
380*5f4c09ddSEd Maste ub.bl.bl_len = (uint32_t)iov.iov_len;
381*5f4c09ddSEd Maste ub.bl.bl_version = BL_VERSION;
382*5f4c09ddSEd Maste ub.bl.bl_type = (uint32_t)e;
383*5f4c09ddSEd Maste
384*5f4c09ddSEd Maste if (bl_getsock(b, &ub.bl.bl_ss, sa, slen, ctx) == -1)
385*5f4c09ddSEd Maste return -1;
386*5f4c09ddSEd Maste
387*5f4c09ddSEd Maste
388*5f4c09ddSEd Maste ub.bl.bl_salen = slen;
389*5f4c09ddSEd Maste memcpy(ub.bl.bl_data, ctx, ctxlen);
390*5f4c09ddSEd Maste
391*5f4c09ddSEd Maste msg.msg_name = NULL;
392*5f4c09ddSEd Maste msg.msg_namelen = 0;
393*5f4c09ddSEd Maste msg.msg_iov = &iov;
394*5f4c09ddSEd Maste msg.msg_iovlen = 1;
395*5f4c09ddSEd Maste msg.msg_flags = 0;
396*5f4c09ddSEd Maste
397*5f4c09ddSEd Maste msg.msg_control = ua.ctrl;
398*5f4c09ddSEd Maste msg.msg_controllen = sizeof(ua.ctrl);
399*5f4c09ddSEd Maste
400*5f4c09ddSEd Maste cmsg = CMSG_FIRSTHDR(&msg);
401*5f4c09ddSEd Maste cmsg->cmsg_len = CMSG_LEN(sizeof(int));
402*5f4c09ddSEd Maste cmsg->cmsg_level = SOL_SOCKET;
403*5f4c09ddSEd Maste cmsg->cmsg_type = SCM_RIGHTS;
404*5f4c09ddSEd Maste
405*5f4c09ddSEd Maste memcpy(CMSG_DATA(cmsg), &pfd, sizeof(pfd));
406*5f4c09ddSEd Maste
407*5f4c09ddSEd Maste tried = 0;
408*5f4c09ddSEd Maste again:
409*5f4c09ddSEd Maste if (bl_init(b, false) == -1)
410*5f4c09ddSEd Maste return -1;
411*5f4c09ddSEd Maste
412*5f4c09ddSEd Maste if ((sendmsg(b->b_fd, &msg, 0) == -1) && tried++ < NTRIES) {
413*5f4c09ddSEd Maste bl_reset(b, false);
414*5f4c09ddSEd Maste goto again;
415*5f4c09ddSEd Maste }
416*5f4c09ddSEd Maste return tried >= NTRIES ? -1 : 0;
417*5f4c09ddSEd Maste }
418*5f4c09ddSEd Maste
419*5f4c09ddSEd Maste bl_info_t *
bl_recv(bl_t b)420*5f4c09ddSEd Maste bl_recv(bl_t b)
421*5f4c09ddSEd Maste {
422*5f4c09ddSEd Maste struct msghdr msg;
423*5f4c09ddSEd Maste struct iovec iov;
424*5f4c09ddSEd Maste union {
425*5f4c09ddSEd Maste char ctrl[CMSG_SPACE(sizeof(int)) + CMSG_SPACE(CRED_SIZE)];
426*5f4c09ddSEd Maste uint32_t fd;
427*5f4c09ddSEd Maste CRED_TYPE sc;
428*5f4c09ddSEd Maste } ua;
429*5f4c09ddSEd Maste struct cmsghdr *cmsg;
430*5f4c09ddSEd Maste CRED_TYPE *sc;
431*5f4c09ddSEd Maste union {
432*5f4c09ddSEd Maste bl_message_t bl;
433*5f4c09ddSEd Maste char buf[512];
434*5f4c09ddSEd Maste } ub;
435*5f4c09ddSEd Maste int got;
436*5f4c09ddSEd Maste ssize_t rlen;
437*5f4c09ddSEd Maste size_t rem;
438*5f4c09ddSEd Maste bl_info_t *bi = &b->b_info;
439*5f4c09ddSEd Maste
440*5f4c09ddSEd Maste got = 0;
441*5f4c09ddSEd Maste memset(bi, 0, sizeof(*bi));
442*5f4c09ddSEd Maste
443*5f4c09ddSEd Maste iov.iov_base = ub.buf;
444*5f4c09ddSEd Maste iov.iov_len = sizeof(ub);
445*5f4c09ddSEd Maste
446*5f4c09ddSEd Maste msg.msg_name = NULL;
447*5f4c09ddSEd Maste msg.msg_namelen = 0;
448*5f4c09ddSEd Maste msg.msg_iov = &iov;
449*5f4c09ddSEd Maste msg.msg_iovlen = 1;
450*5f4c09ddSEd Maste msg.msg_flags = 0;
451*5f4c09ddSEd Maste
452*5f4c09ddSEd Maste msg.msg_control = ua.ctrl;
453*5f4c09ddSEd Maste msg.msg_controllen = sizeof(ua.ctrl) + 100;
454*5f4c09ddSEd Maste
455*5f4c09ddSEd Maste rlen = recvmsg(b->b_fd, &msg, 0);
456*5f4c09ddSEd Maste if (rlen == -1) {
457*5f4c09ddSEd Maste bl_log(b->b_fun, LOG_ERR, "%s: recvmsg failed (%s)", __func__,
458*5f4c09ddSEd Maste strerror(errno));
459*5f4c09ddSEd Maste return NULL;
460*5f4c09ddSEd Maste }
461*5f4c09ddSEd Maste
462*5f4c09ddSEd Maste for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
463*5f4c09ddSEd Maste if (cmsg->cmsg_level != SOL_SOCKET) {
464*5f4c09ddSEd Maste bl_log(b->b_fun, LOG_ERR,
465*5f4c09ddSEd Maste "%s: unexpected cmsg_level %d",
466*5f4c09ddSEd Maste __func__, cmsg->cmsg_level);
467*5f4c09ddSEd Maste continue;
468*5f4c09ddSEd Maste }
469*5f4c09ddSEd Maste switch (cmsg->cmsg_type) {
470*5f4c09ddSEd Maste case SCM_RIGHTS:
471*5f4c09ddSEd Maste if (cmsg->cmsg_len != CMSG_LEN(sizeof(int))) {
472*5f4c09ddSEd Maste bl_log(b->b_fun, LOG_ERR,
473*5f4c09ddSEd Maste "%s: unexpected cmsg_len %d != %zu",
474*5f4c09ddSEd Maste __func__, cmsg->cmsg_len,
475*5f4c09ddSEd Maste CMSG_LEN(2 * sizeof(int)));
476*5f4c09ddSEd Maste continue;
477*5f4c09ddSEd Maste }
478*5f4c09ddSEd Maste memcpy(&bi->bi_fd, CMSG_DATA(cmsg), sizeof(bi->bi_fd));
479*5f4c09ddSEd Maste got |= GOT_FD;
480*5f4c09ddSEd Maste break;
481*5f4c09ddSEd Maste #ifdef CRED_MESSAGE
482*5f4c09ddSEd Maste case CRED_MESSAGE:
483*5f4c09ddSEd Maste sc = (void *)CMSG_DATA(cmsg);
484*5f4c09ddSEd Maste bi->bi_uid = sc->CRED_SC_UID;
485*5f4c09ddSEd Maste bi->bi_gid = sc->CRED_SC_GID;
486*5f4c09ddSEd Maste got |= GOT_CRED;
487*5f4c09ddSEd Maste break;
488*5f4c09ddSEd Maste #endif
489*5f4c09ddSEd Maste default:
490*5f4c09ddSEd Maste bl_log(b->b_fun, LOG_ERR,
491*5f4c09ddSEd Maste "%s: unexpected cmsg_type %d",
492*5f4c09ddSEd Maste __func__, cmsg->cmsg_type);
493*5f4c09ddSEd Maste continue;
494*5f4c09ddSEd Maste }
495*5f4c09ddSEd Maste
496*5f4c09ddSEd Maste }
497*5f4c09ddSEd Maste
498*5f4c09ddSEd Maste if (got != (GOT_CRED|GOT_FD)) {
499*5f4c09ddSEd Maste bl_log(b->b_fun, LOG_ERR, "message missing %s %s",
500*5f4c09ddSEd Maste #if GOT_CRED != 0
501*5f4c09ddSEd Maste (got & GOT_CRED) == 0 ? "cred" :
502*5f4c09ddSEd Maste #endif
503*5f4c09ddSEd Maste "", (got & GOT_FD) == 0 ? "fd" : "");
504*5f4c09ddSEd Maste return NULL;
505*5f4c09ddSEd Maste }
506*5f4c09ddSEd Maste
507*5f4c09ddSEd Maste rem = (size_t)rlen;
508*5f4c09ddSEd Maste if (rem < sizeof(ub.bl)) {
509*5f4c09ddSEd Maste bl_log(b->b_fun, LOG_ERR, "message too short %zd", rlen);
510*5f4c09ddSEd Maste return NULL;
511*5f4c09ddSEd Maste }
512*5f4c09ddSEd Maste rem -= sizeof(ub.bl);
513*5f4c09ddSEd Maste
514*5f4c09ddSEd Maste if (ub.bl.bl_version != BL_VERSION) {
515*5f4c09ddSEd Maste bl_log(b->b_fun, LOG_ERR, "bad version %d", ub.bl.bl_version);
516*5f4c09ddSEd Maste return NULL;
517*5f4c09ddSEd Maste }
518*5f4c09ddSEd Maste
519*5f4c09ddSEd Maste bi->bi_type = ub.bl.bl_type;
520*5f4c09ddSEd Maste bi->bi_slen = ub.bl.bl_salen;
521*5f4c09ddSEd Maste bi->bi_ss = ub.bl.bl_ss;
522*5f4c09ddSEd Maste #ifndef CRED_MESSAGE
523*5f4c09ddSEd Maste bi->bi_uid = -1;
524*5f4c09ddSEd Maste bi->bi_gid = -1;
525*5f4c09ddSEd Maste #endif
526*5f4c09ddSEd Maste rem = MIN(sizeof(bi->bi_msg), rem);
527*5f4c09ddSEd Maste if (rem == 0)
528*5f4c09ddSEd Maste bi->bi_msg[0] = '\0';
529*5f4c09ddSEd Maste else
530*5f4c09ddSEd Maste strlcpy(bi->bi_msg, ub.bl.bl_data, rem);
531*5f4c09ddSEd Maste return bi;
532*5f4c09ddSEd Maste }
533