1    	/*
2    	 * Copyright 2010-2024 Red Hat, Inc.
3    	 *
4    	 * Author: Angus Salkeld <asalkeld@redhat.com>
5    	 *
6    	 * This file is part of libqb.
7    	 *
8    	 * libqb is free software: you can redistribute it and/or modify
9    	 * it under the terms of the GNU Lesser General Public License as published by
10   	 * the Free Software Foundation, either version 2.1 of the License, or
11   	 * (at your option) any later version.
12   	 *
13   	 * libqb is distributed in the hope that it will be useful,
14   	 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15   	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   	 * GNU Lesser General Public License for more details.
17   	 *
18   	 * You should have received a copy of the GNU Lesser General Public License
19   	 * along with libqb.  If not, see <http://www.gnu.org/licenses/>.
20   	 */
21   	#include "os_base.h"
22   	#include <poll.h>
23   	
24   	#if defined(HAVE_GETPEERUCRED)
25   	#include <ucred.h>
26   	#endif
27   	
28   	#ifdef HAVE_SYS_UN_H
29   	#include <sys/un.h>
30   	#endif /* HAVE_SYS_UN_H */
31   	#ifdef HAVE_SYS_STAT_H
32   	#include <sys/stat.h>
33   	#endif
34   	#ifdef HAVE_SYS_MMAN_H
35   	#include <sys/mman.h>
36   	#endif
37   	
38   	#include <qb/qbatomic.h>
39   	#include <qb/qbipcs.h>
40   	#include <qb/qbloop.h>
41   	#include <qb/qbdefs.h>
42   	
43   	#include "util_int.h"
44   	#include "ipc_int.h"
45   	
46   	struct ipc_auth_ugp {
47   		uid_t uid;
48   		gid_t gid;
49   		pid_t pid;
50   	};
51   	
52   	struct ipc_auth_data {
53   		int32_t sock;
54   		struct qb_ipcs_service *s;
55   		union {
56   			struct qb_ipc_connection_request req;
57   			struct qb_ipc_connection_response res;
58   		} msg;
59   		struct msghdr msg_recv;
60   		struct iovec iov_recv;
61   		struct ipc_auth_ugp ugp;
62   	
63   		size_t processed;
64   		size_t len;
65   	
66   	#ifdef SO_PASSCRED
67   		char *cmsg_cred;
68   	#endif
69   	
70   	};
71   	
72   	static int32_t qb_ipcs_us_connection_acceptor(int fd, int revent, void *data);
73   	
74   	ssize_t
75   	qb_ipc_us_send(struct qb_ipc_one_way *one_way, const void *msg, size_t len)
76   	{
77   		int32_t result;
78   		int32_t processed = 0;
79   		char *rbuf = (char *)msg;
80   	
81   		qb_sigpipe_ctl(QB_SIGPIPE_IGNORE);
82   	
83   	retry_send:
(1) Event tainted_data_return: Called function "send(one_way->u.us.sock, &rbuf[processed], len - processed, MSG_NOSIGNAL)", and a possible return value may be less than zero.
(2) Event cast_overflow: An assign that casts to a different type, which might trigger an overflow.
Also see events: [overflow][overflow][overflow][return_overflow]
84   		result = send(one_way->u.us.sock,
85   			      &rbuf[processed], len - processed, MSG_NOSIGNAL);
86   	
(3) Event path: Condition "result == -1", taking false branch.
(7) Event path: Condition "result == -1", taking true branch.
(11) Event path: Condition "result == -1", taking true branch.
(15) Event path: Condition "result == -1", taking false branch.
(19) Event path: Condition "result == -1", taking true branch.
(23) Event path: Condition "result == -1", taking false branch.
87   		if (result == -1) {
(8) Event path: Condition "*__errno_location() == 11", taking true branch.
(9) Event path: Condition "processed > 0", taking true branch.
(12) Event path: Condition "*__errno_location() == 11", taking true branch.
(13) Event path: Condition "processed > 0", taking true branch.
(20) Event path: Condition "*__errno_location() == 11", taking true branch.
(21) Event path: Condition "processed > 0", taking true branch.
88   			if (errno == EAGAIN && processed > 0) {
(10) Event path: Jumping to label "retry_send".
(14) Event path: Jumping to label "retry_send".
(22) Event path: Jumping to label "retry_send".
89   				goto retry_send;
90   			} else {
91   				qb_sigpipe_ctl(QB_SIGPIPE_DEFAULT);
92   				return -errno;
93   			}
94   		}
95   	
(4) Event overflow: The expression "processed" is considered to have possibly overflowed.
(16) Event overflow: The expression "processed += result" is deemed overflowed because at least one of its arguments has overflowed.
(24) Event overflow: The expression "processed += result" is deemed underflowed because at least one of its arguments has underflowed.
Also see events: [tainted_data_return][cast_overflow][return_overflow]
96   		processed += result;
(5) Event path: Condition "processed != len", taking true branch.
(17) Event path: Condition "processed != len", taking true branch.
(25) Event path: Condition "processed != len", taking false branch.
97   		if (processed != len) {
(6) Event path: Jumping to label "retry_send".
(18) Event path: Jumping to label "retry_send".
98   			goto retry_send;
99   		}
100  	
101  		qb_sigpipe_ctl(QB_SIGPIPE_DEFAULT);
102  	
CID (unavailable; MK=cbed7ac5a68cc2984d193270fe5bb53b) (#2 of 2): Overflowed return value (INTEGER_OVERFLOW):
(26) Event return_overflow: "processed", which might have underflowed, is returned from the function.
Also see events: [tainted_data_return][cast_overflow][overflow][overflow][overflow]
103  		return processed;
104  	}
105  	
106  	static ssize_t
107  	qb_ipc_us_recv_msghdr(struct ipc_auth_data *data)
108  	{
109  		char *msg = (char *) &data->msg;
110  		int32_t result;
111  	
112  		qb_sigpipe_ctl(QB_SIGPIPE_IGNORE);
113  	
114  	retry_recv:
115  		data->msg_recv.msg_iov->iov_base = &msg[data->processed];
116  		data->msg_recv.msg_iov->iov_len = data->len - data->processed;
117  	
118  		result = recvmsg(data->sock, &data->msg_recv, MSG_NOSIGNAL | MSG_WAITALL);
119  		if (result == -1 && errno == EAGAIN) {
120  			qb_sigpipe_ctl(QB_SIGPIPE_DEFAULT);
121  			return -EAGAIN;
122  		}
123  		if (result == -1) {
124  			qb_sigpipe_ctl(QB_SIGPIPE_DEFAULT);
125  			return -errno;
126  		}
127  		if (result == 0) {
128  			qb_sigpipe_ctl(QB_SIGPIPE_DEFAULT);
129  			qb_util_log(LOG_DEBUG,
130  				    "recv(fd %d) got 0 bytes assuming ENOTCONN", data->sock);
131  			return -ENOTCONN;
132  		}
133  	
134  		data->processed += result;
135  		if (data->processed != data->len) {
136  			goto retry_recv;
137  		}
138  		qb_sigpipe_ctl(QB_SIGPIPE_DEFAULT);
139  		assert(data->processed == data->len);
140  	
141  		return data->processed;
142  	}
143  	
144  	int32_t
145  	qb_ipc_us_sock_error_is_disconnected(int err)
146  	{
147  		if (err >= 0) {
148  			return QB_FALSE;
149  		} else if (err == -EAGAIN ||
150  		    err == -ETIMEDOUT ||
151  		    err == -EINTR ||
152  	#ifdef EWOULDBLOCK
153  		    err == -EWOULDBLOCK ||
154  	#endif
155  		    err == -EMSGSIZE ||
156  		    err == -ENOMSG ||
157  		    err == -EINVAL) {
158  			return QB_FALSE;
159  		}
160  		return QB_TRUE;
161  	}
162  	
163  	int32_t
164  	qb_ipc_us_ready(struct qb_ipc_one_way * ow_data,
165  			struct qb_ipc_one_way * ow_conn,
166  			int32_t ms_timeout, int32_t events)
167  	{
168  		struct pollfd ufds[2];
169  		int32_t poll_events;
170  		int numfds = 1;
171  		int i;
172  	
173  		ufds[0].fd = ow_data->u.us.sock;
174  		ufds[0].events = events;
175  		ufds[0].revents = 0;
176  	
177  		if (ow_conn && ow_data != ow_conn) {
178  			numfds++;
179  			ufds[1].fd = ow_conn->u.us.sock;
180  			ufds[1].events = POLLIN;
181  			ufds[1].revents = 0;
182  		}
183  		poll_events = poll(ufds, numfds, ms_timeout);
184  		if ((poll_events == -1 && errno == EINTR) || poll_events == 0) {
185  			return -EAGAIN;
186  		} else if (poll_events == -1) {
187  			return -errno;
188  		}
189  		for (i = 0; i < poll_events; i++) {
190  			if (ufds[i].revents & POLLERR) {
191  				qb_util_log(LOG_DEBUG, "poll(fd %d) got POLLERR",
192  					    ufds[i].fd);
193  				return -ENOTCONN;
194  			} else if (ufds[i].revents & POLLHUP) {
195  				qb_util_log(LOG_DEBUG, "poll(fd %d) got POLLHUP",
196  					    ufds[i].fd);
197  				return -ENOTCONN;
198  			} else if (ufds[i].revents & POLLNVAL) {
199  				qb_util_log(LOG_DEBUG, "poll(fd %d) got POLLNVAL",
200  					    ufds[i].fd);
201  				return -ENOTCONN;
202  			} else if (ufds[i].revents == 0) {
203  				qb_util_log(LOG_DEBUG, "poll(fd %d) zero revents",
204  					    ufds[i].fd);
205  				return -ENOTCONN;
206  			}
207  		}
208  		return 0;
209  	}
210  	
211  	/*
212  	 * recv an entire message - and try hard to get all of it.
213  	 */
214  	ssize_t
215  	qb_ipc_us_recv(struct qb_ipc_one_way * one_way,
216  		       void *msg, size_t len, int32_t timeout)
217  	{
218  		int32_t result;
219  		int32_t final_rc = 0;
220  		int32_t processed = 0;
221  		int32_t to_recv = len;
222  		char *data = msg;
223  	
224  		qb_sigpipe_ctl(QB_SIGPIPE_IGNORE);
225  	
226  	retry_recv:
227  		result = recv(one_way->u.us.sock, &data[processed], to_recv,
228  			      MSG_NOSIGNAL | MSG_WAITALL);
229  	
230  		if (result == -1) {
231  			if (errno == EAGAIN && (processed > 0 || timeout == -1)) {
232  				result = qb_ipc_us_ready(one_way, NULL, timeout, POLLIN);
233  				if (result == 0 || result == -EAGAIN) {
234  					goto retry_recv;
235  				}
236  				final_rc = result;
237  				goto cleanup_sigpipe;
238  			} else if (errno == ECONNRESET || errno == EPIPE) {
239  				final_rc = -ENOTCONN;
240  				goto cleanup_sigpipe;
241  			} else {
242  				final_rc = -errno;
243  				goto cleanup_sigpipe;
244  			}
245  		}
246  	
247  		if (result == 0) {
248  			final_rc = -ENOTCONN;
249  			goto cleanup_sigpipe;
250  		}
251  		processed += result;
252  		to_recv -= result;
253  		if (processed != len) {
254  			goto retry_recv;
255  		}
256  		final_rc = processed;
257  	
258  	cleanup_sigpipe:
259  		qb_sigpipe_ctl(QB_SIGPIPE_DEFAULT);
260  		return final_rc;
261  	}
262  	
263  	static int32_t
264  	qb_ipcc_stream_sock_connect(const char *socket_name, int32_t * sock_pt)
265  	{
266  		int32_t request_fd;
267  		struct sockaddr_un address;
268  		int32_t res = 0;
269  	
270  		request_fd = socket(PF_UNIX, SOCK_STREAM, 0);
271  		if (request_fd == -1) {
272  			return -errno;
273  		}
274  	
275  		qb_socket_nosigpipe(request_fd);
276  	
277  		res = qb_sys_fd_nonblock_cloexec_set(request_fd);
278  		if (res < 0) {
279  			goto error_connect;
280  		}
281  	
282  		memset(&address, 0, sizeof(struct sockaddr_un));
283  		address.sun_family = AF_UNIX;
284  	#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
285  		address.sun_len = QB_SUN_LEN(&address);
286  	#endif
287  	
288  		if (!use_filesystem_sockets()) {
289  			snprintf(address.sun_path + 1, UNIX_PATH_MAX - 1, "%s", socket_name);
290  		} else {
291  			snprintf(address.sun_path, sizeof(address.sun_path), "%s/%s", SOCKETDIR,
292  				 socket_name);
293  		}
294  	
295  		if (connect(request_fd, (struct sockaddr *)&address,
296  			    QB_SUN_LEN(&address)) == -1) {
297  			res = -errno;
298  			goto error_connect;
299  		}
300  	
301  		*sock_pt = request_fd;
302  		return 0;
303  	
304  	error_connect:
305  		close(request_fd);
306  		*sock_pt = -1;
307  	
308  		return res;
309  	}
310  	
311  	void
312  	qb_ipcc_us_sock_close(int32_t sock)
313  	{
314  		shutdown(sock, SHUT_RDWR);
315  		close(sock);
316  	}
317  	
318  	static int32_t
319  	qb_ipc_auth_creds(struct ipc_auth_data *data)
320  	{
321  		int32_t res = 0;
322  	
323  		/*
324  		 * currently support getpeerucred, getpeereid, and SO_PASSCRED credential
325  		 * retrieval mechanisms for various Platforms
326  		 */
327  	#ifdef HAVE_GETPEERUCRED
328  		/*
329  		 * Solaris and some BSD systems
330  		 */
331  		{
332  			ucred_t *uc = NULL;
333  	
334  			if (getpeerucred(data->sock, &uc) == 0) {
335  				res = 0;
336  				data->ugp.uid = ucred_geteuid(uc);
337  				data->ugp.gid = ucred_getegid(uc);
338  				data->ugp.pid = ucred_getpid(uc);
339  				ucred_free(uc);
340  			} else {
341  				res = -errno;
342  			}
343  		}
344  	#elif defined(HAVE_GETPEEREID)
345  		/*
346  		* Usually MacOSX systems
347  		*/
348  		{
349  			/*
350  			* TODO get the peer's pid.
351  			* c->pid = ?;
352  			*/
353  			if (getpeereid(data->sock, &data->ugp.uid, &data->ugp.gid) == 0) {
354  				res = 0;
355  			} else {
356  				res = -errno;
357  			}
358  		}
359  	
360  	#elif defined(SO_PASSCRED)
361  		/*
362  		* Usually Linux systems
363  		*/
364  		{
365  			struct ucred cred;
366  			struct cmsghdr *cmsg;
367  	
368  			res = -EINVAL;
369  			for (cmsg = CMSG_FIRSTHDR(&data->msg_recv); cmsg != NULL;
370  				cmsg = CMSG_NXTHDR(&data->msg_recv, cmsg)) {
371  				if (cmsg->cmsg_type != SCM_CREDENTIALS)
372  					continue;
373  	
374  				/* Validate that the control message contains a full ucred structure */
375  				if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct ucred))) {
376  					qb_util_log(LOG_WARNING,
377  						    "received malformed credential message (len=%zu, expected=%zu)",
378  						    (size_t)cmsg->cmsg_len, CMSG_LEN(sizeof(struct ucred)));
379  					continue;
380  				}
381  	
382  				memcpy(&cred, CMSG_DATA(cmsg), sizeof(struct ucred));
383  				res = 0;
384  				data->ugp.pid = cred.pid;
385  				data->ugp.uid = cred.uid;
386  				data->ugp.gid = cred.gid;
387  				break;
388  			}
389  		}
390  	#else /* no credentials */
391  		data->ugp.pid = 0;
392  		data->ugp.uid = 0;
393  		data->ugp.gid = 0;
394  		res = -ENOTSUP;
395  	#endif /* no credentials */
396  	
397  		return res;
398  	}
399  	
400  	static void
401  	destroy_ipc_auth_data(struct ipc_auth_data *data)
402  	{
403  		if (data->s) {
404  			qb_ipcs_unref(data->s);
405  		}
406  	
407  	#ifdef SO_PASSCRED
408  		free(data->cmsg_cred);
409  	#endif
410  		free(data);
411  	}
412  	
413  	static struct ipc_auth_data *
414  	init_ipc_auth_data(int sock, size_t len)
415  	{
416  		struct ipc_auth_data *data = calloc(1, sizeof(struct ipc_auth_data));
417  	
418  		if (data == NULL) {
419  			return NULL;
420  		}
421  	
422  		data->msg_recv.msg_iov = &data->iov_recv;
423  		data->msg_recv.msg_iovlen = 1;
424  		data->msg_recv.msg_name = 0;
425  		data->msg_recv.msg_namelen = 0;
426  	
427  	#ifdef SO_PASSCRED
428  		data->cmsg_cred = calloc(1, CMSG_SPACE(sizeof(struct ucred)));
429  		if (data->cmsg_cred == NULL) {
430  			destroy_ipc_auth_data(data);
431  			return NULL;
432  		}
433  		data->msg_recv.msg_control = (void *)data->cmsg_cred;
434  		data->msg_recv.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
435  	#endif
436  	#if defined(QB_SOLARIS) && !defined(_XPG4_2)
437  		data->msg_recv.msg_accrights = 0;
438  		data->msg_recv.msg_accrightslen = 0;
439  	#else
440  		data->msg_recv.msg_flags = 0;
441  	#endif /* QB_SOLARIS */
442  	
443  		data->len = len;
444  		data->iov_recv.iov_base = (void *)&data->msg;
445  		data->iov_recv.iov_len = data->len;
446  		data->sock = sock;
447  	
448  		return data;
449  	}
450  	
451  	int32_t
452  	qb_ipcc_us_setup_connect(struct qb_ipcc_connection *c,
453  				 struct qb_ipc_connection_response *r)
454  	{
455  		int32_t res;
456  		struct qb_ipc_connection_request request;
457  	#ifdef QB_LINUX
458  		int on = 1;
459  	#endif
460  	
461  		res = qb_ipcc_stream_sock_connect(c->name, &c->setup.u.us.sock);
462  		if (res != 0) {
463  			return res;
464  		}
465  	#ifdef QB_LINUX
466  		res = setsockopt(c->setup.u.us.sock, SOL_SOCKET, SO_PASSCRED, &on,
467  				 sizeof(on));
468  		if (res != 0) {
469  			int err = errno;
470  			qb_ipcc_us_sock_close(c->setup.u.us.sock);
471  			errno = err;
472  			return res;
473  		}
474  	#endif
475  	
476  		memset(&request, 0, sizeof(request));
477  		request.hdr.id = QB_IPC_MSG_AUTHENTICATE;
478  		request.hdr.size = sizeof(request);
479  		request.max_msg_size = c->setup.max_msg_size;
480  		res = qb_ipc_us_send(&c->setup, &request, request.hdr.size);
481  		if (res < 0) {
482  			qb_ipcc_us_sock_close(c->setup.u.us.sock);
483  			return res;
484  		}
485  	
486  		/* ... To be continued ... (when the FD is active) */
487  		return 0;
488  	}
489  	
490  	#define AUTH_RECV_MAX_RETRIES 10
491  	#define AUTH_RECV_SLEEP_TIME_US 100
492  	
493  	/* Called from ipcc_connect_continue() when async connect socket is active */
494  	int qb_ipcc_setup_connect_continue(struct qb_ipcc_connection *c, struct qb_ipc_connection_response *r)
495  	{
496  		struct ipc_auth_data *data;
497  		int32_t res;
498  		int res1;
499  		int retry_count = 0;
500  	#ifdef QB_LINUX
501  		int off = 0;
502  	#endif
503  		data = init_ipc_auth_data(c->setup.u.us.sock, sizeof(struct qb_ipc_connection_response));
504  		if (data == NULL) {
505  			qb_ipcc_us_sock_close(c->setup.u.us.sock);
506  			return -ENOMEM;
507  		}
508  	retry:
509  		res = qb_ipc_us_recv_msghdr(data);
510  		if (res == -EAGAIN && ++retry_count < AUTH_RECV_MAX_RETRIES) {
511  			struct timespec ts = {0,  AUTH_RECV_SLEEP_TIME_US*QB_TIME_NS_IN_USEC};
512  			struct timespec ts_left = {0, 0};
513  			nanosleep(&ts, &ts_left);
514  			goto retry;
515  		}
516  	
517  	#ifdef QB_LINUX
518  		res1 = setsockopt(c->setup.u.us.sock, SOL_SOCKET, SO_PASSCRED, &off,
519  				 sizeof(off));
520  		if (res1 != 0) {
521  			int err = errno;
522  			destroy_ipc_auth_data(data);
523  			errno = err;
524  			return res;
525  		}
526  	#endif
527  	
528  		if (res != data->len) {
529  			destroy_ipc_auth_data(data);
530  			return res;
531  		}
532  	
533  		memcpy(r, &data->msg.res, sizeof(struct qb_ipc_connection_response));
534  	
535  		qb_ipc_auth_creds(data);
536  		c->egid = data->ugp.gid;
537  		c->euid = data->ugp.uid;
538  		c->server_pid = data->ugp.pid;
539  	
540  		destroy_ipc_auth_data(data);
541  	
542  		return r->hdr.error;
543  	}
544  	
545  	/*
546  	 **************************************************************************
547  	 * SERVER
548  	 */
549  	
550  	int32_t
551  	qb_ipcs_us_publish(struct qb_ipcs_service * s)
552  	{
553  		struct sockaddr_un un_addr;
554  		int32_t res;
555  	#ifdef SO_PASSCRED
556  		int on = 1;
557  	#endif
558  	
559  		/*
560  		 * Create socket for IPC clients, name socket, listen for connections
561  		 */
562  		s->server_sock = socket(PF_UNIX, SOCK_STREAM, 0);
563  		if (s->server_sock == -1) {
564  			res = -errno;
565  			qb_util_perror(LOG_ERR, "Cannot create server socket");
566  			return res;
567  		}
568  	
569  		res = qb_sys_fd_nonblock_cloexec_set(s->server_sock);
570  		if (res < 0) {
571  			goto error_close;
572  		}
573  	
574  		memset(&un_addr, 0, sizeof(struct sockaddr_un));
575  		un_addr.sun_family = AF_UNIX;
576  	#if defined(QB_BSD) || defined(QB_DARWIN)
577  		un_addr.sun_len = SUN_LEN(&un_addr);
578  	#endif
579  	
580  		qb_util_log(LOG_INFO, "server name: %s", s->name);
581  	
582  		if (!use_filesystem_sockets()) {
583  			snprintf(un_addr.sun_path + 1, UNIX_PATH_MAX - 1, "%s", s->name);
584  		}
585  		else {
586  			struct stat stat_out;
587  			res = stat(SOCKETDIR, &stat_out);
588  			if (res == -1 || (res == 0 && !S_ISDIR(stat_out.st_mode))) {
589  				res = -errno;
590  				qb_util_log(LOG_CRIT,
591  					    "Required directory not present %s",
592  					    SOCKETDIR);
593  				goto error_close;
594  			}
595  			snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s/%s", SOCKETDIR,
596  				 s->name);
597  			unlink(un_addr.sun_path);
598  		}
599  	
600  		res = bind(s->server_sock, (struct sockaddr *)&un_addr,
601  			   QB_SUN_LEN(&un_addr));
602  		if (res) {
603  			res = -errno;
604  			qb_util_perror(LOG_ERR, "Could not bind AF_UNIX (%s)",
605  				       un_addr.sun_path);
606  			goto error_close;
607  	        }
608  	
609  		/*
610  		 * Allow everyone to write to the socket since the IPC layer handles
611  		 * security automatically
612  		 */
613  		if (use_filesystem_sockets()) {
614  		        (void)chmod(un_addr.sun_path, S_IRWXU | S_IRWXG | S_IRWXO);
615  	        }
616  	#ifdef SO_PASSCRED
617  		(void)setsockopt(s->server_sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
618  	#endif
619  		if (listen(s->server_sock, SERVER_BACKLOG) == -1) {
620  			qb_util_perror(LOG_ERR, "socket listen failed");
621  		}
622  	
623  		res = s->poll_fns.dispatch_add(s->poll_priority, s->server_sock,
624  					       POLLIN | POLLPRI | POLLNVAL,
625  					       s, qb_ipcs_us_connection_acceptor);
626  		return res;
627  	
628  	error_close:
629  		close(s->server_sock);
630  		return res;
631  	}
632  	
633  	int32_t
634  	qb_ipcs_us_withdraw(struct qb_ipcs_service * s)
635  	{
636  		qb_util_log(LOG_INFO, "withdrawing server sockets");
637  		(void)s->poll_fns.dispatch_del(s->server_sock);
638  		shutdown(s->server_sock, SHUT_RDWR);
639  	
640  		if (use_filesystem_sockets()) {
641  			struct sockaddr_un sockname;
642  			socklen_t socklen = sizeof(sockname);
643  			if ((getsockname(s->server_sock, (struct sockaddr *)&sockname, &socklen) == 0) &&
644  			    sockname.sun_family == AF_UNIX) {
645  	#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
646  				/*
647  				 * Terminating NUL on FreeBSD is not part of the sun_path.
648  				 * Add it to use sun_path as a parameter of unlink
649  				 */
650  				sockname.sun_path[sockname.sun_len - offsetof(struct sockaddr_un, sun_path)] = '\0';
651  	#endif
652  				unlink(sockname.sun_path);
653  			}
654  		}
655  	
656  		close(s->server_sock);
657  		s->server_sock = -1;
658  		return 0;
659  	}
660  	
661  	static int32_t
662  	handle_new_connection(struct qb_ipcs_service *s,
663  			      int32_t auth_result,
664  			      int32_t sock,
665  			      void *msg, size_t len, struct ipc_auth_ugp *ugp)
666  	{
667  		struct qb_ipcs_connection *c = NULL;
668  		struct qb_ipc_connection_request *req = msg;
669  		int32_t res = auth_result;
670  		int32_t res2 = 0;
671  		uint32_t max_buffer_size = QB_MAX(req->max_msg_size, s->max_buffer_size);
672  		struct qb_ipc_connection_response response;
673  		const char suffix[] = "/qb";
674  		int desc_len;
675  	
676  		c = qb_ipcs_connection_alloc(s);
677  		if (c == NULL) {
678  			qb_ipcc_us_sock_close(sock);
679  			return -ENOMEM;
680  		}
681  	
682  		c->receive_buf = calloc(1, max_buffer_size);
683  		if (c->receive_buf == NULL) {
684  			free(c);
685  			qb_ipcc_us_sock_close(sock);
686  			return -ENOMEM;
687  		}
688  		c->setup.u.us.sock = sock;
689  		c->request.max_msg_size = max_buffer_size;
690  		c->response.max_msg_size = max_buffer_size;
691  		c->event.max_msg_size = max_buffer_size;
692  		c->pid = ugp->pid;
693  		c->auth.uid = c->euid = ugp->uid;
694  		c->auth.gid = c->egid = ugp->gid;
695  		c->auth.mode = 0600;
696  		c->stats.client_pid = ugp->pid;
697  	
698  		memset(&response, 0, sizeof(response));
699  	
700  	#if defined(QB_LINUX) || defined(QB_CYGWIN)
701  		desc_len = snprintf(c->description, CONNECTION_DESCRIPTION - sizeof suffix,
702  				    "/dev/shm/qb-%d-%d-%d-XXXXXX", s->pid, ugp->pid, c->setup.u.us.sock);
703  		if (desc_len < 0) {
704  			res = -errno;
705  			goto send_response;
706  		}
707  		if (desc_len >= CONNECTION_DESCRIPTION - sizeof suffix) {
708  			res = -ENAMETOOLONG;
709  			goto send_response;
710  		}
711  		if (mkdtemp(c->description) == NULL) {
712  			res = -errno;
713  			goto send_response;
714  		}
715  		if (chmod(c->description, 0770)) {
716  			res = -errno;
717  			goto send_response;
718  		}
719  		/* chown may fail if not root, but log it */
720  		if (chown(c->description, c->auth.uid, c->auth.gid) != 0) {
721  			qb_util_perror(LOG_WARNING, "failed to chown directory (%s)",
722  				       c->description);
723  		}
724  	
725  		/* We can't pass just a directory spec to the clients */
726  		memcpy(c->description + desc_len, suffix, sizeof suffix);
727  	#else
728  		desc_len = snprintf(c->description, CONNECTION_DESCRIPTION,
729  				    "%d-%d-%d", s->pid, ugp->pid, c->setup.u.us.sock);
730  		if (desc_len < 0) {
731  			res = -errno;
732  			goto send_response;
733  		}
734  		if (desc_len >= CONNECTION_DESCRIPTION) {
735  			res = -ENAMETOOLONG;
736  			goto send_response;
737  		}
738  	#endif
739  	
740  	
741  	
742  		if (auth_result == 0 && c->service->serv_fns.connection_accept) {
743  			res = c->service->serv_fns.connection_accept(c,
744  								     c->euid, c->egid);
745  		}
746  		if (res != 0) {
747  			goto send_response;
748  		}
749  	
750  		qb_util_log(LOG_DEBUG, "IPC credentials authenticated (%s)",
751  			    c->description);
752  	
753  		if (s->funcs.connect) {
754  			res = s->funcs.connect(s, c, &response);
755  			if (res != 0) {
756  				goto send_response;
757  			}
758  		}
759  		/*
760  		 * The connection is good, add it to the active connection list
761  		 */
762  		c->state = QB_IPCS_CONNECTION_ACTIVE;
763  		qb_list_add(&c->list, &s->connections);
764  	
765  	send_response:
766  		response.hdr.id = QB_IPC_MSG_AUTHENTICATE;
767  		response.hdr.size = sizeof(response);
768  		response.hdr.error = res;
769  		if (res == 0) {
770  			response.connection = (intptr_t) c;
771  			response.connection_type = s->type;
772  			response.max_msg_size = c->request.max_msg_size;
773  			s->stats.active_connections++;
774  		}
775  	
776  		res2 = qb_ipc_us_send(&c->setup, &response, response.hdr.size);
777  		if (res == 0 && res2 != response.hdr.size) {
778  			res = res2;
779  		}
780  	
781  		if (res == 0) {
782  			qb_ipcs_connection_ref(c);
783  			if (s->serv_fns.connection_created) {
784  				s->serv_fns.connection_created(c);
785  			}
786  			if (c->state == QB_IPCS_CONNECTION_ACTIVE) {
787  				c->state = QB_IPCS_CONNECTION_ESTABLISHED;
788  			}
789  			qb_ipcs_connection_unref(c);
790  		} else {
791  			if (res == -EACCES) {
792  				qb_util_log(LOG_INFO, "IPC connection credentials rejected (%s)",
793  					    c->description);
794  			} else if (res == -EAGAIN) {
795  				qb_util_log(LOG_INFO, "IPC connection not ready (%s)",
796  					    c->description);
797  			} else {
798  				qb_util_perror(LOG_INFO, "IPC connection setup failed (%s)",
799  					       c->description);
800  				errno = -res;
801  			}
802  	
803  			if (c->state == QB_IPCS_CONNECTION_INACTIVE) {
804  				/* This removes the initial alloc ref */
805  				qb_ipcs_connection_unref(c);
806  			        qb_ipcc_us_sock_close(sock);
807  			} else {
808  				qb_ipcs_disconnect(c);
809  			}
810  		}
811  		return res;
812  	}
813  	
814  	static int32_t
815  	process_auth(int32_t fd, int32_t revents, void *d)
816  	{
817  		struct ipc_auth_data *data = (struct ipc_auth_data *) d;
818  	
819  		int32_t res = 0;
820  		int res1;
821  	#ifdef SO_PASSCRED
822  		int off = 0;
823  	#endif
824  	
825  		if (data->s->server_sock == -1) {
826  			qb_util_log(LOG_DEBUG, "Closing fd (%d) for server shutdown", fd);
827  			res = -ESHUTDOWN;
828  			goto cleanup_and_return;
829  		}
830  	
831  		if (revents & POLLNVAL) {
832  			qb_util_log(LOG_DEBUG, "NVAL conn fd (%d)", fd);
833  			res = -EINVAL;
834  			goto cleanup_and_return;
835  		}
836  		if (revents & POLLHUP) {
837  			qb_util_log(LOG_DEBUG, "HUP conn fd (%d)", fd);
838  			res = -ESHUTDOWN;
839  			goto cleanup_and_return;
840  		}
841  		if ((revents & POLLIN) == 0) {
842  			return 0;
843  		}
844  	
845  		res = qb_ipc_us_recv_msghdr(data);
846  		if (res == -EAGAIN) {
847  			/* yield to mainloop, Let mainloop call us again */
848  			return 0;
849  		}
850  	
851  		if (res != data->len) {
852  			res = -EIO;
853  			goto cleanup_and_return;
854  		}
855  	
856  		res = qb_ipc_auth_creds(data);
857  	
858  	cleanup_and_return:
859  	#ifdef SO_PASSCRED
860  		res1 = setsockopt(data->sock, SOL_SOCKET, SO_PASSCRED, &off, sizeof(off));
861  		if (res1 != 0) {
862  			int err = errno;
863  			close(data->sock);
864  			errno = err;
865  			return res;
866  		}
867  	#endif
868  	
869  		(void)data->s->poll_fns.dispatch_del(data->sock);
870  	
871  		if (res < 0) {
872  			close(data->sock);
873  		} else if (data->msg.req.hdr.id == QB_IPC_MSG_AUTHENTICATE) {
874  			(void)handle_new_connection(data->s, res, data->sock, &data->msg, data->len, &data->ugp);
875  		} else {
876  			close(data->sock);
877  		}
878  		destroy_ipc_auth_data(data);
879  	
880  		return 1;
881  	}
882  	
883  	static void
884  	qb_ipcs_uc_recv_and_auth(int32_t sock, struct qb_ipcs_service *s)
885  	{
886  		int res = 0;
887  		int res1;
888  		struct ipc_auth_data *data = NULL;
889  	#ifdef SO_PASSCRED
890  		int on = 1;
891  	#endif
892  	
893  		data = init_ipc_auth_data(sock, sizeof(struct qb_ipc_connection_request));
894  		if (data == NULL) {
895  			close(sock);
896  			/* -ENOMEM */
897  			return;
898  		}
899  	
900  		data->s = s;
901  		qb_ipcs_ref(data->s);
902  	
903  	#ifdef SO_PASSCRED
904  		res1 = setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
905  		if (res1 != 0) {
906  			close(sock);
907  			return;
908  		}
909  	#endif
910  	
911  		res = s->poll_fns.dispatch_add(s->poll_priority,
912  		                               data->sock,
913  		                               POLLIN | POLLPRI | POLLNVAL,
914  		                               data, process_auth);
915  		if (res < 0) {
916  			qb_util_log(LOG_DEBUG, "Failed to arrange for AUTH for fd (%d)",
917  			            data->sock);
918  			close(sock);
919  			destroy_ipc_auth_data(data);
920  		}
921  	}
922  	
923  	static int32_t
924  	qb_ipcs_us_connection_acceptor(int fd, int revent, void *data)
925  	{
926  		struct sockaddr_un un_addr;
927  		int32_t new_fd;
928  		struct qb_ipcs_service *s = (struct qb_ipcs_service *)data;
929  		int32_t res;
930  		socklen_t addrlen = sizeof(struct sockaddr_un);
931  	
932  		if (revent & (POLLNVAL | POLLHUP | POLLERR)) {
933  			/*
934  			 * handle shutdown more cleanly.
935  			 */
936  			return -1;
937  		}
938  	
939  	retry_accept:
940  		errno = 0;
941  		new_fd = accept(fd, (struct sockaddr *)&un_addr, &addrlen);
942  		if (new_fd == -1 && errno == EINTR) {
943  			goto retry_accept;
944  		}
945  	
946  		if (new_fd == -1 && errno == EBADF) {
947  			qb_util_perror(LOG_ERR,
948  				       "Could not accept client connection from fd:%d",
949  				       fd);
950  			return -1;
951  		}
952  		if (new_fd == -1) {
953  			qb_util_perror(LOG_ERR, "Could not accept client connection");
954  			/* This is an error, but -1 would indicate disconnect
955  			 * from the poll loop
956  			 */
957  			return 0;
958  		}
959  	
960  		res = qb_sys_fd_nonblock_cloexec_set(new_fd);
961  		if (res < 0) {
962  			close(new_fd);
963  			/* This is an error, but -1 would indicate disconnect
964  			 * from the poll loop
965  			 */
966  			return 0;
967  		}
968  	
969  		qb_ipcs_uc_recv_and_auth(new_fd, s);
970  		return 0;
971  	}
972  	
973  	void remove_tempdir(const char *name)
974  	{
975  	#if defined(QB_LINUX) || defined(QB_CYGWIN)
976  		char dirname[PATH_MAX];
977  		const char *slash = strrchr(name, '/');
978  	
979  		if (slash && slash - name < sizeof dirname) {
980  			memcpy(dirname, name, slash - name);
981  			dirname[slash - name] = '\0';
982  			/* This gets called more than it needs to be really, so we don't check
983  			 * the return code. It's more of a desperate attempt to clean up after ourself
984  			 * in either the server or client.
985  			 */
986  			(void)rmdir(dirname);
987  		}
988  	#endif
989  	}
990