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   	
(8) Event label: Reached label "retry_send".
(13) Event label: Reached label "retry_send".
(19) Event label: Reached label "retry_send".
(24) Event label: Reached label "retry_send".
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 cond_false: Condition "result == -1", taking false branch.
(9) Event cond_true: Condition "result == -1", taking true branch.
(14) Event cond_false: Condition "result == -1", taking false branch.
(20) Event cond_true: Condition "result == -1", taking true branch.
(25) Event cond_false: Condition "result == -1", taking false branch.
87   		if (result == -1) {
(10) Event cond_true: Condition "*__errno_location() == 11", taking true branch.
(11) Event cond_true: Condition "processed > 0", taking true branch.
(21) Event cond_true: Condition "*__errno_location() == 11", taking true branch.
(22) Event cond_true: Condition "processed > 0", taking true branch.
88   			if (errno == EAGAIN && processed > 0) {
(12) Event goto: Jumping to label "retry_send".
(23) Event goto: Jumping to label "retry_send".
89   				goto retry_send;
90   			} else {
91   				qb_sigpipe_ctl(QB_SIGPIPE_DEFAULT);
92   				return -errno;
93   			}
(4) Event if_end: End of if statement.
(15) Event if_end: End of if statement.
(26) Event if_end: End of if statement.
94   		}
95   	
(5) 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.
(27) 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;
(6) Event cond_true: Condition "processed != len", taking true branch.
(17) Event cond_true: Condition "processed != len", taking true branch.
(28) Event cond_false: Condition "processed != len", taking false branch.
97   		if (processed != len) {
(7) Event goto: Jumping to label "retry_send".
(18) Event goto: Jumping to label "retry_send".
98   			goto retry_send;
(29) Event if_end: End of if statement.
99   		}
100  	
101  		qb_sigpipe_ctl(QB_SIGPIPE_DEFAULT);
102  	
(30) 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  				memcpy(&cred, CMSG_DATA(cmsg), sizeof(struct ucred));
375  				res = 0;
376  				data->ugp.pid = cred.pid;
377  				data->ugp.uid = cred.uid;
378  				data->ugp.gid = cred.gid;
379  				break;
380  			}
381  		}
382  	#else /* no credentials */
383  		data->ugp.pid = 0;
384  		data->ugp.uid = 0;
385  		data->ugp.gid = 0;
386  		res = -ENOTSUP;
387  	#endif /* no credentials */
388  	
389  		return res;
390  	}
391  	
392  	static void
393  	destroy_ipc_auth_data(struct ipc_auth_data *data)
394  	{
395  		if (data->s) {
396  			qb_ipcs_unref(data->s);
397  		}
398  	
399  	#ifdef SO_PASSCRED
400  		free(data->cmsg_cred);
401  	#endif
402  		free(data);
403  	}
404  	
405  	static struct ipc_auth_data *
406  	init_ipc_auth_data(int sock, size_t len)
407  	{
408  		struct ipc_auth_data *data = calloc(1, sizeof(struct ipc_auth_data));
409  	
410  		if (data == NULL) {
411  			return NULL;
412  		}
413  	
414  		data->msg_recv.msg_iov = &data->iov_recv;
415  		data->msg_recv.msg_iovlen = 1;
416  		data->msg_recv.msg_name = 0;
417  		data->msg_recv.msg_namelen = 0;
418  	
419  	#ifdef SO_PASSCRED
420  		data->cmsg_cred = calloc(1, CMSG_SPACE(sizeof(struct ucred)));
421  		if (data->cmsg_cred == NULL) {
422  			destroy_ipc_auth_data(data);
423  			return NULL;
424  		}
425  		data->msg_recv.msg_control = (void *)data->cmsg_cred;
426  		data->msg_recv.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
427  	#endif
428  	#if defined(QB_SOLARIS) && !defined(_XPG4_2)
429  		data->msg_recv.msg_accrights = 0;
430  		data->msg_recv.msg_accrightslen = 0;
431  	#else
432  		data->msg_recv.msg_flags = 0;
433  	#endif /* QB_SOLARIS */
434  	
435  		data->len = len;
436  		data->iov_recv.iov_base = (void *)&data->msg;
437  		data->iov_recv.iov_len = data->len;
438  		data->sock = sock;
439  	
440  		return data;
441  	}
442  	
443  	int32_t
444  	qb_ipcc_us_setup_connect(struct qb_ipcc_connection *c,
445  				 struct qb_ipc_connection_response *r)
446  	{
447  		int32_t res;
448  		struct qb_ipc_connection_request request;
449  	#ifdef QB_LINUX
450  		int on = 1;
451  	#endif
452  	
453  		res = qb_ipcc_stream_sock_connect(c->name, &c->setup.u.us.sock);
454  		if (res != 0) {
455  			return res;
456  		}
457  	#ifdef QB_LINUX
458  		res = setsockopt(c->setup.u.us.sock, SOL_SOCKET, SO_PASSCRED, &on,
459  				 sizeof(on));
460  		if (res != 0) {
461  			int err = errno;
462  			qb_ipcc_us_sock_close(c->setup.u.us.sock);
463  			errno = err;
464  			return res;
465  		}
466  	#endif
467  	
468  		memset(&request, 0, sizeof(request));
469  		request.hdr.id = QB_IPC_MSG_AUTHENTICATE;
470  		request.hdr.size = sizeof(request);
471  		request.max_msg_size = c->setup.max_msg_size;
472  		res = qb_ipc_us_send(&c->setup, &request, request.hdr.size);
473  		if (res < 0) {
474  			qb_ipcc_us_sock_close(c->setup.u.us.sock);
475  			return res;
476  		}
477  	
478  		/* ... To be continued ... (when the FD is active) */
479  		return 0;
480  	}
481  	
482  	#define AUTH_RECV_MAX_RETRIES 10
483  	#define AUTH_RECV_SLEEP_TIME_US 100
484  	
485  	/* Called from ipcc_connect_continue() when async connect socket is active */
486  	int qb_ipcc_setup_connect_continue(struct qb_ipcc_connection *c, struct qb_ipc_connection_response *r)
487  	{
488  		struct ipc_auth_data *data;
489  		int32_t res;
490  		int res1;
491  		int retry_count = 0;
492  	#ifdef QB_LINUX
493  		int off = 0;
494  	#endif
495  		data = init_ipc_auth_data(c->setup.u.us.sock, sizeof(struct qb_ipc_connection_response));
496  		if (data == NULL) {
497  			qb_ipcc_us_sock_close(c->setup.u.us.sock);
498  			return -ENOMEM;
499  		}
500  	retry:
501  		res = qb_ipc_us_recv_msghdr(data);
502  		if (res == -EAGAIN && ++retry_count < AUTH_RECV_MAX_RETRIES) {
503  			struct timespec ts = {0,  AUTH_RECV_SLEEP_TIME_US*QB_TIME_NS_IN_USEC};
504  			struct timespec ts_left = {0, 0};
505  			nanosleep(&ts, &ts_left);
506  			goto retry;
507  		}
508  	
509  	#ifdef QB_LINUX
510  		res1 = setsockopt(c->setup.u.us.sock, SOL_SOCKET, SO_PASSCRED, &off,
511  				 sizeof(off));
512  		if (res1 != 0) {
513  			int err = errno;
514  			destroy_ipc_auth_data(data);
515  			errno = err;
516  			return res;
517  		}
518  	#endif
519  	
520  		if (res != data->len) {
521  			destroy_ipc_auth_data(data);
522  			return res;
523  		}
524  	
525  		memcpy(r, &data->msg.res, sizeof(struct qb_ipc_connection_response));
526  	
527  		qb_ipc_auth_creds(data);
528  		c->egid = data->ugp.gid;
529  		c->euid = data->ugp.uid;
530  		c->server_pid = data->ugp.pid;
531  	
532  		destroy_ipc_auth_data(data);
533  	
534  		return r->hdr.error;
535  	}
536  	
537  	/*
538  	 **************************************************************************
539  	 * SERVER
540  	 */
541  	
542  	int32_t
543  	qb_ipcs_us_publish(struct qb_ipcs_service * s)
544  	{
545  		struct sockaddr_un un_addr;
546  		int32_t res;
547  	#ifdef SO_PASSCRED
548  		int on = 1;
549  	#endif
550  	
551  		/*
552  		 * Create socket for IPC clients, name socket, listen for connections
553  		 */
554  		s->server_sock = socket(PF_UNIX, SOCK_STREAM, 0);
555  		if (s->server_sock == -1) {
556  			res = -errno;
557  			qb_util_perror(LOG_ERR, "Cannot create server socket");
558  			return res;
559  		}
560  	
561  		res = qb_sys_fd_nonblock_cloexec_set(s->server_sock);
562  		if (res < 0) {
563  			goto error_close;
564  		}
565  	
566  		memset(&un_addr, 0, sizeof(struct sockaddr_un));
567  		un_addr.sun_family = AF_UNIX;
568  	#if defined(QB_BSD) || defined(QB_DARWIN)
569  		un_addr.sun_len = SUN_LEN(&un_addr);
570  	#endif
571  	
572  		qb_util_log(LOG_INFO, "server name: %s", s->name);
573  	
574  		if (!use_filesystem_sockets()) {
575  			snprintf(un_addr.sun_path + 1, UNIX_PATH_MAX - 1, "%s", s->name);
576  		}
577  		else {
578  			struct stat stat_out;
579  			res = stat(SOCKETDIR, &stat_out);
580  			if (res == -1 || (res == 0 && !S_ISDIR(stat_out.st_mode))) {
581  				res = -errno;
582  				qb_util_log(LOG_CRIT,
583  					    "Required directory not present %s",
584  					    SOCKETDIR);
585  				goto error_close;
586  			}
587  			snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s/%s", SOCKETDIR,
588  				 s->name);
589  			unlink(un_addr.sun_path);
590  		}
591  	
592  		res = bind(s->server_sock, (struct sockaddr *)&un_addr,
593  			   QB_SUN_LEN(&un_addr));
594  		if (res) {
595  			res = -errno;
596  			qb_util_perror(LOG_ERR, "Could not bind AF_UNIX (%s)",
597  				       un_addr.sun_path);
598  			goto error_close;
599  	        }
600  	
601  		/*
602  		 * Allow everyone to write to the socket since the IPC layer handles
603  		 * security automatically
604  		 */
605  		if (use_filesystem_sockets()) {
606  		        (void)chmod(un_addr.sun_path, S_IRWXU | S_IRWXG | S_IRWXO);
607  	        }
608  	#ifdef SO_PASSCRED
609  		(void)setsockopt(s->server_sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
610  	#endif
611  		if (listen(s->server_sock, SERVER_BACKLOG) == -1) {
612  			qb_util_perror(LOG_ERR, "socket listen failed");
613  		}
614  	
615  		res = s->poll_fns.dispatch_add(s->poll_priority, s->server_sock,
616  					       POLLIN | POLLPRI | POLLNVAL,
617  					       s, qb_ipcs_us_connection_acceptor);
618  		return res;
619  	
620  	error_close:
621  		close(s->server_sock);
622  		return res;
623  	}
624  	
625  	int32_t
626  	qb_ipcs_us_withdraw(struct qb_ipcs_service * s)
627  	{
628  		qb_util_log(LOG_INFO, "withdrawing server sockets");
629  		(void)s->poll_fns.dispatch_del(s->server_sock);
630  		shutdown(s->server_sock, SHUT_RDWR);
631  	
632  		if (use_filesystem_sockets()) {
633  			struct sockaddr_un sockname;
634  			socklen_t socklen = sizeof(sockname);
635  			if ((getsockname(s->server_sock, (struct sockaddr *)&sockname, &socklen) == 0) &&
636  			    sockname.sun_family == AF_UNIX) {
637  	#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
638  				/*
639  				 * Terminating NUL on FreeBSD is not part of the sun_path.
640  				 * Add it to use sun_path as a parameter of unlink
641  				 */
642  				sockname.sun_path[sockname.sun_len - offsetof(struct sockaddr_un, sun_path)] = '\0';
643  	#endif
644  				unlink(sockname.sun_path);
645  			}
646  		}
647  	
648  		close(s->server_sock);
649  		s->server_sock = -1;
650  		return 0;
651  	}
652  	
653  	static int32_t
654  	handle_new_connection(struct qb_ipcs_service *s,
655  			      int32_t auth_result,
656  			      int32_t sock,
657  			      void *msg, size_t len, struct ipc_auth_ugp *ugp)
658  	{
659  		struct qb_ipcs_connection *c = NULL;
660  		struct qb_ipc_connection_request *req = msg;
661  		int32_t res = auth_result;
662  		int32_t res2 = 0;
663  		uint32_t max_buffer_size = QB_MAX(req->max_msg_size, s->max_buffer_size);
664  		struct qb_ipc_connection_response response;
665  		const char suffix[] = "/qb";
666  		int desc_len;
667  	
668  		c = qb_ipcs_connection_alloc(s);
669  		if (c == NULL) {
670  			qb_ipcc_us_sock_close(sock);
671  			return -ENOMEM;
672  		}
673  	
674  		c->receive_buf = calloc(1, max_buffer_size);
675  		if (c->receive_buf == NULL) {
676  			free(c);
677  			qb_ipcc_us_sock_close(sock);
678  			return -ENOMEM;
679  		}
680  		c->setup.u.us.sock = sock;
681  		c->request.max_msg_size = max_buffer_size;
682  		c->response.max_msg_size = max_buffer_size;
683  		c->event.max_msg_size = max_buffer_size;
684  		c->pid = ugp->pid;
685  		c->auth.uid = c->euid = ugp->uid;
686  		c->auth.gid = c->egid = ugp->gid;
687  		c->auth.mode = 0600;
688  		c->stats.client_pid = ugp->pid;
689  	
690  		memset(&response, 0, sizeof(response));
691  	
692  	#if defined(QB_LINUX) || defined(QB_CYGWIN)
693  		desc_len = snprintf(c->description, CONNECTION_DESCRIPTION - sizeof suffix,
694  				    "/dev/shm/qb-%d-%d-%d-XXXXXX", s->pid, ugp->pid, c->setup.u.us.sock);
695  		if (desc_len < 0) {
696  			res = -errno;
697  			goto send_response;
698  		}
699  		if (desc_len >= CONNECTION_DESCRIPTION - sizeof suffix) {
700  			res = -ENAMETOOLONG;
701  			goto send_response;
702  		}
703  		if (mkdtemp(c->description) == NULL) {
704  			res = -errno;
705  			goto send_response;
706  		}
707  		if (chmod(c->description, 0770)) {
708  			res = -errno;
709  			goto send_response;
710  		}
711  		/* chown can fail because we might not be root */
712  		(void)chown(c->description, c->auth.uid, c->auth.gid);
713  	
714  		/* We can't pass just a directory spec to the clients */
715  		memcpy(c->description + desc_len, suffix, sizeof suffix);
716  	#else
717  		desc_len = snprintf(c->description, CONNECTION_DESCRIPTION,
718  				    "%d-%d-%d", s->pid, ugp->pid, c->setup.u.us.sock);
719  		if (desc_len < 0) {
720  			res = -errno;
721  			goto send_response;
722  		}
723  		if (desc_len >= CONNECTION_DESCRIPTION) {
724  			res = -ENAMETOOLONG;
725  			goto send_response;
726  		}
727  	#endif
728  	
729  	
730  	
731  		if (auth_result == 0 && c->service->serv_fns.connection_accept) {
732  			res = c->service->serv_fns.connection_accept(c,
733  								     c->euid, c->egid);
734  		}
735  		if (res != 0) {
736  			goto send_response;
737  		}
738  	
739  		qb_util_log(LOG_DEBUG, "IPC credentials authenticated (%s)",
740  			    c->description);
741  	
742  		if (s->funcs.connect) {
743  			res = s->funcs.connect(s, c, &response);
744  			if (res != 0) {
745  				goto send_response;
746  			}
747  		}
748  		/*
749  		 * The connection is good, add it to the active connection list
750  		 */
751  		c->state = QB_IPCS_CONNECTION_ACTIVE;
752  		qb_list_add(&c->list, &s->connections);
753  	
754  	send_response:
755  		response.hdr.id = QB_IPC_MSG_AUTHENTICATE;
756  		response.hdr.size = sizeof(response);
757  		response.hdr.error = res;
758  		if (res == 0) {
759  			response.connection = (intptr_t) c;
760  			response.connection_type = s->type;
761  			response.max_msg_size = c->request.max_msg_size;
762  			s->stats.active_connections++;
763  		}
764  	
765  		res2 = qb_ipc_us_send(&c->setup, &response, response.hdr.size);
766  		if (res == 0 && res2 != response.hdr.size) {
767  			res = res2;
768  		}
769  	
770  		if (res == 0) {
771  			qb_ipcs_connection_ref(c);
772  			if (s->serv_fns.connection_created) {
773  				s->serv_fns.connection_created(c);
774  			}
775  			if (c->state == QB_IPCS_CONNECTION_ACTIVE) {
776  				c->state = QB_IPCS_CONNECTION_ESTABLISHED;
777  			}
778  			qb_ipcs_connection_unref(c);
779  		} else {
780  			if (res == -EACCES) {
781  				qb_util_log(LOG_INFO, "IPC connection credentials rejected (%s)",
782  					    c->description);
783  			} else if (res == -EAGAIN) {
784  				qb_util_log(LOG_INFO, "IPC connection not ready (%s)",
785  					    c->description);
786  			} else {
787  				qb_util_perror(LOG_INFO, "IPC connection setup failed (%s)",
788  					       c->description);
789  				errno = -res;
790  			}
791  	
792  			if (c->state == QB_IPCS_CONNECTION_INACTIVE) {
793  				/* This removes the initial alloc ref */
794  				qb_ipcs_connection_unref(c);
795  			        qb_ipcc_us_sock_close(sock);
796  			} else {
797  				qb_ipcs_disconnect(c);
798  			}
799  		}
800  		return res;
801  	}
802  	
803  	static int32_t
804  	process_auth(int32_t fd, int32_t revents, void *d)
805  	{
806  		struct ipc_auth_data *data = (struct ipc_auth_data *) d;
807  	
808  		int32_t res = 0;
809  		int res1;
810  	#ifdef SO_PASSCRED
811  		int off = 0;
812  	#endif
813  	
814  		if (data->s->server_sock == -1) {
815  			qb_util_log(LOG_DEBUG, "Closing fd (%d) for server shutdown", fd);
816  			res = -ESHUTDOWN;
817  			goto cleanup_and_return;
818  		}
819  	
820  		if (revents & POLLNVAL) {
821  			qb_util_log(LOG_DEBUG, "NVAL conn fd (%d)", fd);
822  			res = -EINVAL;
823  			goto cleanup_and_return;
824  		}
825  		if (revents & POLLHUP) {
826  			qb_util_log(LOG_DEBUG, "HUP conn fd (%d)", fd);
827  			res = -ESHUTDOWN;
828  			goto cleanup_and_return;
829  		}
830  		if ((revents & POLLIN) == 0) {
831  			return 0;
832  		}
833  	
834  		res = qb_ipc_us_recv_msghdr(data);
835  		if (res == -EAGAIN) {
836  			/* yield to mainloop, Let mainloop call us again */
837  			return 0;
838  		}
839  	
840  		if (res != data->len) {
841  			res = -EIO;
842  			goto cleanup_and_return;
843  		}
844  	
845  		res = qb_ipc_auth_creds(data);
846  	
847  	cleanup_and_return:
848  	#ifdef SO_PASSCRED
849  		res1 = setsockopt(data->sock, SOL_SOCKET, SO_PASSCRED, &off, sizeof(off));
850  		if (res1 != 0) {
851  			int err = errno;
852  			close(data->sock);
853  			errno = err;
854  			return res;
855  		}
856  	#endif
857  	
858  		(void)data->s->poll_fns.dispatch_del(data->sock);
859  	
860  		if (res < 0) {
861  			close(data->sock);
862  		} else if (data->msg.req.hdr.id == QB_IPC_MSG_AUTHENTICATE) {
863  			(void)handle_new_connection(data->s, res, data->sock, &data->msg, data->len, &data->ugp);
864  		} else {
865  			close(data->sock);
866  		}
867  		destroy_ipc_auth_data(data);
868  	
869  		return 1;
870  	}
871  	
872  	static void
873  	qb_ipcs_uc_recv_and_auth(int32_t sock, struct qb_ipcs_service *s)
874  	{
875  		int res = 0;
876  		int res1;
877  		struct ipc_auth_data *data = NULL;
878  	#ifdef SO_PASSCRED
879  		int on = 1;
880  	#endif
881  	
882  		data = init_ipc_auth_data(sock, sizeof(struct qb_ipc_connection_request));
883  		if (data == NULL) {
884  			close(sock);
885  			/* -ENOMEM */
886  			return;
887  		}
888  	
889  		data->s = s;
890  		qb_ipcs_ref(data->s);
891  	
892  	#ifdef SO_PASSCRED
893  		res1 = setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
894  		if (res1 != 0) {
895  			close(sock);
896  			return;
897  		}
898  	#endif
899  	
900  		res = s->poll_fns.dispatch_add(s->poll_priority,
901  		                               data->sock,
902  		                               POLLIN | POLLPRI | POLLNVAL,
903  		                               data, process_auth);
904  		if (res < 0) {
905  			qb_util_log(LOG_DEBUG, "Failed to arrange for AUTH for fd (%d)",
906  			            data->sock);
907  			close(sock);
908  			destroy_ipc_auth_data(data);
909  		}
910  	}
911  	
912  	static int32_t
913  	qb_ipcs_us_connection_acceptor(int fd, int revent, void *data)
914  	{
915  		struct sockaddr_un un_addr;
916  		int32_t new_fd;
917  		struct qb_ipcs_service *s = (struct qb_ipcs_service *)data;
918  		int32_t res;
919  		socklen_t addrlen = sizeof(struct sockaddr_un);
920  	
921  		if (revent & (POLLNVAL | POLLHUP | POLLERR)) {
922  			/*
923  			 * handle shutdown more cleanly.
924  			 */
925  			return -1;
926  		}
927  	
928  	retry_accept:
929  		errno = 0;
930  		new_fd = accept(fd, (struct sockaddr *)&un_addr, &addrlen);
931  		if (new_fd == -1 && errno == EINTR) {
932  			goto retry_accept;
933  		}
934  	
935  		if (new_fd == -1 && errno == EBADF) {
936  			qb_util_perror(LOG_ERR,
937  				       "Could not accept client connection from fd:%d",
938  				       fd);
939  			return -1;
940  		}
941  		if (new_fd == -1) {
942  			qb_util_perror(LOG_ERR, "Could not accept client connection");
943  			/* This is an error, but -1 would indicate disconnect
944  			 * from the poll loop
945  			 */
946  			return 0;
947  		}
948  	
949  		res = qb_sys_fd_nonblock_cloexec_set(new_fd);
950  		if (res < 0) {
951  			close(new_fd);
952  			/* This is an error, but -1 would indicate disconnect
953  			 * from the poll loop
954  			 */
955  			return 0;
956  		}
957  	
958  		qb_ipcs_uc_recv_and_auth(new_fd, s);
959  		return 0;
960  	}
961  	
962  	void remove_tempdir(const char *name)
963  	{
964  	#if defined(QB_LINUX) || defined(QB_CYGWIN)
965  		char dirname[PATH_MAX];
966  		char *slash = strrchr(name, '/');
967  	
968  		if (slash && slash - name < sizeof dirname) {
969  			memcpy(dirname, name, slash - name);
970  			dirname[slash - name] = '\0';
971  			/* This gets called more than it needs to be really, so we don't check
972  			 * the return code. It's more of a desperate attempt to clean up after ourself
973  			 * in either the server or client.
974  			 */
975  			(void)rmdir(dirname);
976  		}
977  	#endif
978  	}
979